C# 弹出USB外接硬盘(U盘)

时间:2020-12-09 18:01:00

最近一个项目需要通过代码来弹出USB外接硬盘设备,经过google找到了下面这个类库:

http://www.codeproject.com/Articles/13530/Eject-USB-disks-using-C

不过这个类库只能在x86下使用,因此需要修改以下内容,使其适用于x64平台

修改DeviceClass为以下代码:

public List<Device> Devices
        {
            get
            {
                if (_devices == null)
                {
                    _devices = new List<Device>();
                    int index = 0;
                    while (true)
                    {
                        Native.SP_DEVICE_INTERFACE_DATA interfaceData = new Native.SP_DEVICE_INTERFACE_DATA();
                        interfaceData.cbSize = (UInt32)Marshal.SizeOf(interfaceData);

                        if (!Native.SetupDiEnumDeviceInterfaces(_deviceInfoSet, IntPtr.Zero, ref _classGuid, (UInt32)index, ref interfaceData))
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != Native.ERROR_NO_MORE_ITEMS)
                                throw new Win32Exception(error);
                            break;
                        }
                        Native.SP_DEVINFO_DATA devData = new Native.SP_DEVINFO_DATA();
                        IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(devData));
                        Marshal.StructureToPtr(devData, p, true);
                        UInt32 size = 0;
                        if (!Native.SetupDiGetDeviceInterfaceDetail(_deviceInfoSet, ref interfaceData, IntPtr.Zero, 0, ref size, p))
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != Native.ERROR_INSUFFICIENT_BUFFER)
                                throw new Win32Exception(error);
                        }
                        Native.SP_DEVICE_INTERFACE_DETAIL_DATA detailDataBuffer = new Native.SP_DEVICE_INTERFACE_DETAIL_DATA();
                        if (IntPtr.Size == 8) // for 64 bit operating systems
                        {
                            detailDataBuffer.cbSize = 8;
                        }
                        else
                        {
                            detailDataBuffer.cbSize = 4 + Marshal.SystemDefaultCharSize; // for 32 bit systems
                        }
                        IntPtr pBuf = Marshal.AllocHGlobal(Marshal.SizeOf(detailDataBuffer));

                        Marshal.StructureToPtr(detailDataBuffer, pBuf, true);

                        if (!Native.SetupDiGetDeviceInterfaceDetail(_deviceInfoSet, ref interfaceData, pBuf, size, ref size, p))
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != Native.ERROR_INSUFFICIENT_BUFFER)
                                throw new Win32Exception(error);
                        }
                        devData = (Native.SP_DEVINFO_DATA)Marshal.PtrToStructure(p, typeof(Native.SP_DEVINFO_DATA));
                        Marshal.FreeHGlobal(p);

                        detailDataBuffer = (Native.SP_DEVICE_INTERFACE_DETAIL_DATA)Marshal.PtrToStructure(pBuf, typeof(Native.SP_DEVICE_INTERFACE_DETAIL_DATA));
                        Marshal.FreeHGlobal(pBuf);

                        string devicePath = detailDataBuffer.DevicePath;
                        Native.STORAGE_DEVICE_NUMBER storageDeviceNumber = GetDeviceNumber(devicePath);
                        Device device = CreateDevice(this, devData, devicePath, storageDeviceNumber.DeviceNumber);
                        _devices.Add(device);

                        index++;
                    }
                    _devices.Sort();
                }
                return _devices;
            }
        }

  添加以下函数到DeviceClass.cs

internal Native.STORAGE_DEVICE_NUMBER GetDeviceNumber(string devicePath)
        {
            IntPtr hFile = Native.CreateFile(devicePath.TrimEnd('\\'), 0, 0, IntPtr.Zero, Native.OPEN_EXISTING, 0, IntPtr.Zero);
            if (hFile.ToInt32() == Native.INVALID_HANDLE_VALUE)
                throw new Win32Exception(Marshal.GetLastWin32Error());
            int bytesReturned;
            Native.STORAGE_DEVICE_NUMBER storageDeviceNumber = new Native.STORAGE_DEVICE_NUMBER();
            int size = Marshal.SizeOf(storageDeviceNumber);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                if (!Native.DeviceIoControl(hFile, Native.IOCTL_STORAGE_GET_DEVICE_NUMBER, IntPtr.Zero, 0, buffer, size, out bytesReturned, IntPtr.Zero))
                {
                    // do nothing here on purpose
                }
            }
            finally
            {
                Native.CloseHandle(hFile);
            }
            if (bytesReturned > 0)
            {
                storageDeviceNumber = (Native.STORAGE_DEVICE_NUMBER)Marshal.PtrToStructure(buffer, typeof(Native.STORAGE_DEVICE_NUMBER));
            }
            Marshal.FreeHGlobal(buffer);
            return storageDeviceNumber;
        }

  Native.cs 添加:

        [StructLayout(LayoutKind.Sequential)]
        internal struct STORAGE_DEVICE_NUMBER
        {
            public int DeviceType;
            public int DeviceNumber;
            public int PartitionNumber;
        }

        internal const int IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080;

  修改Volumn.cs

IntPtr hFile = Native.CreateFile(@"\\.\" + LogicalDrive, Native.GENERIC_READ, Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE, IntPtr.Zero, Native.OPEN_EXISTING, 0, IntPtr.Zero);

  为:

IntPtr hFile = Native.CreateFile(@"\\.\" + LogicalDrive, 0, Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE, IntPtr.Zero, Native.OPEN_EXISTING, 0, IntPtr.Zero);

  

修改Native.cs

     [StructLayout(LayoutKind.Sequential)]
        internal class SP_DEVINFO_DATA
        {
            internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
            internal Guid classGuid = Guid.Empty; // temp
            internal int devInst = 0; // dumy
            internal int reserved = 0;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal int cbSize;
            internal short devicePath;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal class SP_DEVICE_INTERFACE_DATA
        {
            internal int cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
            internal Guid interfaceClassGuid = Guid.Empty; // temp
            internal int flags = 0;
            internal int reserved = 0;
        }

  为:

[StructLayout(LayoutKind.Sequential)]
        internal class SP_DEVINFO_DATA
        {
            internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
            internal Guid classGuid = Guid.Empty; // temp
            internal int devInst = 0; // dumy
            internal IntPtr reserved = IntPtr.Zero;
        }


        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal Int32 cbSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            internal string DevicePath;
        }


        [StructLayout(LayoutKind.Sequential)]
        internal struct SP_DEVICE_INTERFACE_DATA
        {
            internal UInt32 cbSize;
            internal Guid interfaceClassGuid;
            internal UInt32 flags;
            internal UIntPtr reserved;
        }

  修改Volume.cs 

                                IntPtr extentPtr = new IntPtr(buffer.ToInt32() + Marshal.SizeOf(typeof(long)) + i * Marshal.SizeOf(typeof(Native.DISK_EXTENT)));

  为

                                IntPtr extentPtr = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(typeof(long)) + i * Marshal.SizeOf(typeof(Native.DISK_EXTENT)));

  

源代码下载