通过 C#弹出USB设备

我一直在寻找一种通过 C # 代码弹出 USB 设备的简短方法,所以我自己编码了一个小类,但它根本不起作用。由于没有弹出窗口显示“锁定成功!”我认为问题依赖于“LockVolume”功能,但我不知道在哪里。

我一直在寻找一种通过 C # 代码弹出 USB 设备的简短方法,所以我自己编码了一个小类,但它根本不起作用。由于没有弹出窗口显示“锁定成功!”我认为问题依赖于“LockVolume”功能,但我不知道在哪里。

有人看到我犯的错误吗?

class USBEject
{
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr CreateFile(
         string lpFileName,
         uint dwDesiredAccess,
         uint dwShareMode,
         IntPtr SecurityAttributes,
         uint dwCreationDisposition,
         uint dwFlagsAndAttributes,
         IntPtr hTemplateFile
    );
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(
        IntPtr hDevice, 
        uint dwIoControlCode,
        IntPtr lpInBuffer, 
        uint nInBufferSize,
        IntPtr lpOutBuffer, 
        uint nOutBufferSize,
        out uint lpBytesReturned, 
        IntPtr lpOverlapped
    );
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(
        IntPtr hDevice, 
        uint dwIoControlCode,
        byte[] lpInBuffer, 
        uint nInBufferSize,
        IntPtr lpOutBuffer, 
        uint nOutBufferSize,
        out uint lpBytesReturned, 
        IntPtr lpOverlapped
    );
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr hObject);
    private IntPtr handle = IntPtr.Zero;
    const int GENERIC_READ = 0x80000000;
    const int GENERIC_WRITE = 0x40000000;
    const int FILE_SHARE_READ = 0x1;
    const int FILE_SHARE_WRITE = 0x2;
    const int FSCTL_LOCK_VOLUME = 0x00090018;
    const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
    const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
    const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
    /// <summary>
    /// Constructor for the USBEject class
    /// </summary>
    /// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
    public USBEject(string driveLetter)
    {
        string filename = @"\\.\" + driveLetter[0] + ":";
        handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
    }
    public bool Eject()
    {
        if (LockVolume(handle) && DismountVolume(handle))
        {
            PreventRemovalOfVolume(handle, false);
            return AutoEjectVolume(handle);
        }
        return false;
    }
    private bool LockVolume(IntPtr handle)
    {
        uint byteReturned;
        for (int i = 0; i < 10; i++)
        {
            if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
            {
                System.Windows.Forms.MessageBox.Show("Lock success!");
                return true;
            }
            Thread.Sleep(500);
        }
        return false;
    }
    private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
    {
        byte[] buf = new byte[1];
        uint retVal;
        buf[0] = (prevent) ? (byte)1 : (byte)0;
        return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
    }
    private bool DismountVolume(IntPtr handle)
    {
        uint byteReturned;
        return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
    }
    private bool AutoEjectVolume(IntPtr handle)
    {
        uint byteReturned;
        return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
    }
    private bool CloseVolume(IntPtr handle)
    {
        return CloseHandle(handle);
    }
}
6

改变只是一点点你的代码,它如下:

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr CreateFile(
     string lpFileName,
     uint dwDesiredAccess,
     uint dwShareMode,
     IntPtr SecurityAttributes,
     uint dwCreationDisposition,
     uint dwFlagsAndAttributes,
     IntPtr hTemplateFile
);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(
        IntPtr hDevice,
        uint dwIoControlCode,
        IntPtr lpInBuffer,
        uint nInBufferSize,
        IntPtr lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped
    );
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(
        IntPtr hDevice,
        uint dwIoControlCode,
        byte[] lpInBuffer,
        uint nInBufferSize,
        IntPtr lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped
    );
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr hObject);
    private IntPtr handle = IntPtr.Zero;
    const uint GENERIC_READ = 0x80000000;
    const uint GENERIC_WRITE = 0x40000000;
    const int FILE_SHARE_READ = 0x1;
    const int FILE_SHARE_WRITE = 0x2;
    const int FSCTL_LOCK_VOLUME = 0x00090018;
    const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
    const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
    const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
    /// <summary>
    /// Constructor for the USBEject class
    /// </summary>
    /// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
    public IntPtr USBEject(string driveLetter)
    {
        string filename = @"\\.\" + driveLetter[0] + ":";
        return CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
    }
    public bool Eject(IntPtr handle)
    {
        bool result = false;
        if (LockVolume(handle) && DismountVolume(handle))
        {
            PreventRemovalOfVolume(handle, false);
            result = AutoEjectVolume(handle);
        }
        CloseHandle(handle);
        return result;
    }
    private bool LockVolume(IntPtr handle)
    {
        uint byteReturned;
        for (int i = 0; i < 10; i++)
        {
            if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
            {
                System.Windows.Forms.MessageBox.Show("Lock success!");
                return true;
            }
            Thread.Sleep(500);
        }
        return false;
    }
    private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
    {
        byte[] buf = new byte[1];
        uint retVal;
        buf[0] = (prevent) ? (byte)1 : (byte)0;
        return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
    }
    private bool DismountVolume(IntPtr handle)
    {
        uint byteReturned;
        return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
    }
    private bool AutoEjectVolume(IntPtr handle)
    {
        uint byteReturned;
        return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
    }
    private bool CloseVolume(IntPtr handle)
    {
        return CloseHandle(handle);
    }

所以你可以用两种方式使用它:

        handle = USBEject("D:");
        Eject(handle);

或直接:

        Eject(USBEject("D:"));

它适用于我的 Windows 10 机器(预览 14291)

3

通过对CreateFile调用使用 Roger Deep 的一些代码找到了我的问题的答案。

我的代码删除 WPF 窗口内的 USB 驱动器:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    EjectDrive('K');
}
void EjectDrive(char driveLetter)
{
    string path = @"\\.\" + driveLetter + @":";
    IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
    if ((long)handle == -1)
    {
        MessageBox.Show("Unable to open drive " + driveLetter);
        return;
    }
    int dummy = 0;
    DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,
        IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
    CloseHandle(handle);
    MessageBox.Show("OK to remove drive.");
}
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr CreateFile
    (string filename, uint desiredAccess,
        uint shareMode, IntPtr securityAttributes,
        int creationDisposition, int flagsAndAttributes,
        IntPtr templateFile);
[DllImport("kernel32")]
private static extern int DeviceIoControl
    (IntPtr deviceHandle, uint ioControlCode,
        IntPtr inBuffer, int inBufferSize,
        IntPtr outBuffer, int outBufferSize,
        ref int bytesReturned, IntPtr overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
0

这是我从 powershell 脚本转换的一些代码。您需要以管理员权限运行,并且它可以“卸载”USB 驱动器。但是,当您尝试拔下 USB 驱动器并再次插入时,它不会显示为驱动器号。(要解决此问题,您需要键入“WindowsKey-X”并选择 Disk-Manager 以将驱动器重新分配给 USB 设备。(如果有人知道如何解决此问题,请提交)。

// Right click Project and Add Reference to System.Management.dll
using System.Management;
string mq = "SELECT * FROM Win32_Volume Where Name = 'E:\\'"; 
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
foreach (ManagementObject mo in ms.Get())
{
    mo["DriveLetter"] = null;
    mo.Put();       
    ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
    inParams["Force"] = false;  
    inParams["Permanent"] = false;
    mo.InvokeMethod("Dismount", inParams, null);
}

请注意,powershell 脚本也有弹出后重新连接 USB 设备的相同问题。

$vol = get-wmiobject -Class Win32_Volume | 
    where{$_.Name -eq 'E:\'}         
$vol.DriveLetter = $null  
$vol.Put()  
$vol.Dismount($false, $false)

这是我刚刚写的使用 WMI 管理可移动 USB 驱动器的安装和卸载的类:

using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Management; //<-- right-click on project and add reference
using System.Collections.Generic;
using System.Text.RegularExpressions;
// This Class implements Mount/Unmount for USB Removable Drives
//  in a way similar to "Disk Manager" in the Control Panel.
//
//  Currently, It doesn't implement "Eject" like when you right
//    right-click on the USB icon on lower right of screen.
//    The "Unmount" is similar to "Eject" except it dosn't
//    cleanup the registry so that the USB drive can be automatically
//    recognized again without manually mounting it from "Disk Manager"
//    If somebody knows how to fix this class to gain this function...
//       please post it to their thread.  Thanks.
namespace WPM {
    public struct UsbDriveItem_t {
        public int    Index;
        public string DeviceId;
        public char   DriveLetter;
        public string Label;
        public override string ToString() {
            if (Index < 0)
                return "<none>";
            else 
                return String.Format("{0}: {1}", DriveLetter, Label);
        }               
    };
    delegate void UsbEvent();
    class UsbDriveRemovable {
        public static int Unmount(char DriveLetter) {
            bool success = ValidateAdmin("UsbDriveRemovable.Unmount()");
            if (!success) return -1;
            string Name = "'" + DriveLetter + ":\\\\'";
            string mq   = "SELECT * FROM Win32_Volume Where Name = " + Name;
            ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
            ManagementObjectCollection mc = ms.Get();
            foreach (ManagementObject mo in mc) {
                var DriveLetterI  = mo["DriveLetter"].ToString();
                mo["DriveLetter"] = null;
                mo.Put();
                ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
                inParams["Force"] = false;
                inParams["Permanent"] = false;
                ManagementBaseObject outParams = mo.InvokeMethod("Dismount", inParams, null);
                string rc = outParams["ReturnValue"].ToString();
                mo.Dispose();
            }
            mc.Dispose();
            ms.Dispose();
            return 0;
        }
        public static int Mount(string DeviceId, char Letter = '?') {
            bool success = ValidateAdmin("UsbDriveRemovable.Mount()");
            if (!success) return -1;
            if (Letter == '?' || Letter == '#') {
                GetFirstUnsedLetter(out Letter);
            }
            string FixDeviceId = Regex.Replace(DeviceId, @"\\", @"\\");
            string mq = "SELECT * FROM Win32_Volume WHERE DeviceId = '"
                + FixDeviceId
                + "'";
            ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
            ManagementObjectCollection mc = ms.Get();
            foreach (ManagementObject mo in mc) {
                ManagementBaseObject inParams = mo.GetMethodParameters("AddMountPoint");
                inParams["Directory"] = Letter + ":\\";
                ManagementBaseObject outParams = mo.InvokeMethod("AddMountPoint", inParams, null);
                string rc = outParams["ReturnValue"].ToString();
                mo.Dispose();
            }
            mc.Dispose();
            ms.Dispose();
            return 0;
        }
        /*List<UsbDriveItem_t>*/ 
        public static int ListDrives(ref List<UsbDriveItem_t> DriveList) {
            DriveList.Clear();
            string mq = "SELECT * FROM Win32_Volume Where DriveType = '2'";
            ManagementObjectSearcher ms   = new ManagementObjectSearcher(mq);
            ManagementObjectCollection mc = ms.Get();
            int count = 0;
            foreach (ManagementObject mo in mc) {
                UsbDriveItem_t item = new UsbDriveItem_t();
                item.Index       = count;
                item.Label       = (mo["Label"] == null)       ? "<none>" : mo["Label"].ToString();
                item.DriveLetter = (mo["DriveLetter"] == null) ? '#' : mo["DriveLetter"].ToString()[0];
                item.DeviceId    = (mo["DeviceId"] == null)    ? "<none>" : mo["DeviceId"].ToString();
                DriveList.Add(item);
                mo.Dispose();
            }
            count++;
            mc.Dispose();
            ms.Dispose();
            return 0;
        }
        public static void MountItem(UsbDriveItem_t DriveItem) {            
            char   DriveLetter = DriveItem.DriveLetter;
            string DriveLabel  = DriveItem.Label;
            string DeviceId    = DriveItem.DeviceId;
            // Mount Drive if its not already Mounted
            if (DriveLetter == '#') {
                UsbDriveRemovable.GetFirstUnsedLetter(out DriveLetter);
                UsbDriveRemovable.Mount(DeviceId, DriveLetter);
            }
            return; 
        }
        public static void UnmountItem(UsbDriveItem_t DriveItem) {      
            char   DriveLetter = DriveItem.DriveLetter;         
            UsbDriveRemovable.Unmount(DriveLetter);
            return;
        }
        public static int GetFirstUnsedLetter(out char Letter) {
            bool[] alphabet = new bool[26];
            for (int i=0; i < 26; i++) {
                alphabet[i] = false;
            }
            string mq = "SELECT * FROM Win32_Volume";
            ManagementObjectSearcher ms   = new ManagementObjectSearcher(mq);
            ManagementObjectCollection mc = ms.Get();
            foreach (ManagementObject mo in mc) {
                if (mo["DriveLetter"] != null) {
                    char cc      = mo["DriveLetter"].ToString()[0];
                    int  ci      = char.ToUpper(cc) - 65;
                    alphabet[ci] = true;
                }
                mo.Dispose();
            }
            mc.Dispose();
            ms.Dispose();
            int found = -1;
            for (int i=3; i < 26; i++) {
                if (alphabet[i] == false) {
                    found = i;
                    break;
                }
            }
            if (found >= 0) {
                Letter = (char)(found + 65);
                return 0;
            }
            else {
                Letter = '?';
                return -1;
            }
        }
        public static object
            RegisterInsertEvent(UsbEvent InsertEvent) {
            var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
            var insertWatcher = new ManagementEventWatcher(insertQuery);            
            insertWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
                // string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();              
                Action action = delegate {
                    InsertEvent();
                };
                Application.Current.Dispatcher.BeginInvoke(action);
            };
            insertWatcher.Start();
            return (object)insertWatcher;
        }
        public static object RegisterRemoveEvent(UsbEvent RemoveEvent) {
            var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
            var removeWatcher = new ManagementEventWatcher(removeQuery);
            removeWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
                // string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();              
                Action action = delegate {                  
                    RemoveEvent();
                };
                Application.Current.Dispatcher.BeginInvoke(action);
            };
            removeWatcher.Start();
            return (object)removeWatcher;
        }
        // Mount all UsbRemovable Drives that are not currently mounted
        public static int MountAll() {
            List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
            ListDrives(ref DriveList);
            foreach (UsbDriveItem_t item in DriveList) {
                if (item.DriveLetter == '?') {
                    Mount(item.DeviceId);
                }
            }
            return 0;
        }
        // Unmount all UsbRemovable Drives
        public static int UnmountAll() {
            List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
            ListDrives(ref DriveList);
            foreach (UsbDriveItem_t item in DriveList) {
                if (item.DriveLetter != '?') {
                    Unmount(item.DriveLetter);
                }
            }
            return 0;
        }
        public static bool Is()
        {
            var id   = System.Security.Prinl.WindowsIdentity.GetCurrent();
            var prin = new System.Security.Prinl.WindowsPrinl(id);
            return prin.IsInRole(
                System.Security.Prinl.WindowsBuiltInRole.);
        }
        public static bool ValidateAdmin(string CalledFrom = null) {
            if (CalledFrom == null) {
                CalledFrom = "";
            }
            if (!Is()) {
                string msg = "Please rerun this application with admin privileges.\r\n\r\n"
                + "Access denied to call " + CalledFrom + "\r\n\r\n";
                MessageBox.Show(msg, "ERROR");
                return false;
            }
            return true;
        }
        public static void StartExplorer(char DriveLetter) 
        {
            var proc1 = new System.Diagnostics.Process();
            proc1.StartInfo.FileName               = @"C:\\Windows\\System32\\explorer.exe";
            proc1.StartInfo.Arguments              = DriveLetter.ToString();
            proc1.StartInfo.CreateNoWindow         = true;
            proc1.StartInfo.UseShellExecute        = false;
            proc1.StartInfo.RedirectStandardOutput = true;
            proc1.StartInfo.RedirectStandardError  = true;
            proc1.Start();
            proc1.WaitForExit();
            string proc1out = proc1.StandardOutput.ReadToEnd();
            string proc1err = proc1.StandardError.ReadToEnd();
            //if (proc1.ExitCode != 0) {
            //  string msg = proc1out + "\r\n\r\n" + proc1err;
            //  MessageBox.Show(msg, "Error: Mountvol /R");
            //}
            proc1.Close();                  
        }       
    } //class
} //namespace
/*  DOESN'T WORK WELL...
        // Kludge to get USB Drive to be recognized again
        void UsbCleanup() {
            var proc1 = new System.Diagnostics.Process();
            proc1.StartInfo.FileName               = @"C:\\Windows\\System32\\mountvol.exe";
            proc1.StartInfo.Arguments              = @"/R";
            proc1.StartInfo.CreateNoWindow         = true;
            proc1.StartInfo.UseShellExecute        = false;
            proc1.StartInfo.RedirectStandardOutput = true;
            proc1.StartInfo.RedirectStandardError  = true;
            proc1.Start();
            proc1.WaitForExit();
            string proc1out = proc1.StandardOutput.ReadToEnd();
            string proc1err = proc1.StandardError.ReadToEnd();
            if (proc1.ExitCode != 0) {
                string msg = proc1out + "\r\n\r\n" + proc1err;
                MessageBox.Show(msg, "Error: Mountvol /R");
            }
            proc1.Close();
            var proc2 = new System.Diagnostics.Process();
            proc2.StartInfo.FileName               = @"C:\\Windows\\System32\\mountvol.exe";
            proc2.StartInfo.Arguments              = @"/E";
            proc2.StartInfo.CreateNoWindow         = true;
            proc2.StartInfo.UseShellExecute        = false;
            proc2.StartInfo.RedirectStandardOutput = true;
            proc2.StartInfo.RedirectStandardError  = true;
            proc2.Start();
            proc2.WaitForExit();
            string proc2out = proc2.StandardOutput.ReadToEnd();
            string proc2err = proc2.StandardError.ReadToEnd();
            if (proc2.ExitCode != 0) {
                string msg = proc1out + "\r\n\r\n" + proc1err;
                MessageBox.Show(msg, "Error: Mountvol /E");
            }
            proc2.Close();
            return;
        }
*/
0

您可以将以下 PowerShell 转换为 C #:

$Eject = New-Object -comObject Shell.Application
$Eject.NameSpace(17).PName($usbDrvLetter+“:”).InvokeVerb(“Eject”)

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(844)
如何将列号(例如127)转换为Excel列(例如AA)
上一篇
Photoshop文本效果的 CSS
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(55条)