• USB设备的插入和弹出的监听以及软弹出可移动媒体(如Windows的移除USB设备) .


    一、监听USB设备的插入和弹出

    当USB设备插入或者弹出时,Windows会产生一条全局消息:WM_DEVICECHANGE

    我们需要做的是,获得这条消息的wParam参数,如果为DBT_DEVICEARRIVAL则表示有设备插入并可用,

    如果是DBT_DEVICEREMOVECOMPLETE则表示有设备已经移除。再查看lParam参数为DBT_DEVTYP_VOLUME时,

    就可以取出DEV_BROADCAST_VOLUME结构的卷号dbcv_unitmask,就知道是哪个卷被插入或者弹出。

    代码片段如下:

    1. using System;  
    2. using System.Runtime.InteropServices;  
    3. /// <summary>   
    4. /// 监听设备的插入和拔出   
    5. /// </summary>   
    6. public class DriveDetector  
    7. {  
    8.     /// <summary>   
    9.     /// 设备插入事件   
    10.     /// </summary>   
    11.     public event EventHandler<DriveDectctorEventArgs> DeviceArrived = null;  
    12.     /// <summary>   
    13.     /// 设备拔出事件   
    14.     /// </summary>   
    15.     public event EventHandler<DriveDectctorEventArgs> DeviceRemoved = null;  
    16.     /// <summary>   
    17.     /// 消息处理(HwndSourceHook委托的签名)   
    18.     /// </summary>   
    19.     /// <param name="hwnd"></param>   
    20.     /// <param name="msg"></param>   
    21.     /// <param name="wParam"></param>   
    22.     /// <param name="lParam"></param>   
    23.     /// <param name="handled"></param>   
    24.     /// <returns></returns>   
    25.     public IntPtr WndProc(  
    26.         IntPtr hwnd,  
    27.         int msg,  
    28.         IntPtr wParam,  
    29.         IntPtr lParam,  
    30.         ref bool handled)  
    31.     {  
    32.         if (msg == NativeConstants.WM_DEVICECHANGE)  
    33.         {  
    34. #warning USB设备检测目前只支持32位系统)   
    35.             switch (wParam.ToInt32())  
    36.             {  
    37.                 case NativeConstants.DBT_DEVICEARRIVAL:  
    38.                     {  
    39.                         var devType = Marshal.ReadInt32(lParam, 4);  
    40.                         if (devType == NativeConstants.DBT_DEVTYP_VOLUME)  
    41.                         {  
    42.                             var drive = GetDrive(lParam);  
    43.                             if (DeviceArrived != null)  
    44.                             {  
    45.                                 var args = new DriveDectctorEventArgs(drive);  
    46.                                 DeviceArrived(this, args); //触发设备插入事件   
    47.                             }  
    48.                         }  
    49.                     }  
    50.                     break;  
    51.                 case NativeConstants.DBT_DEVICEREMOVECOMPLETE:  
    52.                     {  
    53.                         var devType = Marshal.ReadInt32(lParam, 4);  
    54.                         if (devType == NativeConstants.DBT_DEVTYP_VOLUME)  
    55.                         {  
    56.                             var drive = GetDrive(lParam);  
    57.                             if (DeviceRemoved != null)  
    58.                             {  
    59.                                 var args = new DriveDectctorEventArgs(drive);  
    60.                                 DeviceRemoved(this, args);  
    61.                             }  
    62.                         }  
    63.                     }  
    64.                     break;  
    65.             }  
    66.         }  
    67.         return IntPtr.Zero;  
    68.     }  
    69.     private static string GetDrive(IntPtr lParam)  
    70.     {  
    71.         var volume = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_VOLUME));  
    72.         var letter = GetLetter(volume.dbcv_unitmask);  
    73.         return string.Format("{0}://", letter);  
    74.     }  
    75.     /// <summary>   
    76.     /// 获得盘符   
    77.     /// </summary>   
    78.     /// <param name="dbcvUnitmask">   
    79.     /// 1 = A   
    80.     /// 2 = B   
    81.     /// 4 = C...   
    82.     /// </param>   
    83.     /// <returns>结果是A~Z的任意一个字符或者为'?'</returns>   
    84.     private static char GetLetter(uint dbcvUnitmask)  
    85.     {  
    86.         const char nona = '?';  
    87.         const string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  
    88.         if (dbcvUnitmask == 0) return nona;  
    89.         var i = 0;  
    90.         var pom = dbcvUnitmask >> 1;  
    91.         while (pom != 0)  
    92.         {  
    93.             pom = pom >> 1;  
    94.             i++;  
    95.         }  
    96.         if (i < drives.Length)  
    97.             return drives[i];  
    98.         return nona;  
    99.     }  
    100.     /*   
    101.       private static void GetLetterTest() 
    102.       { 
    103.           for (int i = 0; i < 67108864; i++) 
    104.           { 
    105.               Console.WriteLine("{0} - {1}", i, GetLetter((uint)i)); 
    106.               i = i << 1; 
    107.           } 
    108. //0 - ? 
    109. //1 - A 
    110. //3 - B 
    111. //7 - C 
    112. //15 - D 
    113. //31 - E 
    114. //63 - F 
    115. //127 - G 
    116. //255 - H 
    117. //511 - I 
    118. //1023 - J 
    119. //2047 - K 
    120. //4095 - L 
    121. //8191 - M 
    122. //16383 - N 
    123. //32767 - O 
    124. //65535 - P 
    125. //131071 - Q 
    126. //262143 - R 
    127. //524287 - S 
    128. //1048575 - T 
    129. //2097151 - U 
    130. //4194303 - V 
    131. //8388607 - W 
    132. //16777215 - X 
    133. //33554431 - Y 
    134. //67108863 - Z 
    135.       }*/  
    136.     /// <summary>   
    137.     /// 设备插入或拔出事件   
    138.     /// </summary>   
    139.     public class DriveDectctorEventArgs : EventArgs  
    140.     {  
    141.         /// <summary>   
    142.         /// 获得设备卷标   
    143.         /// </summary>   
    144.         public string Drive { get; private set; }  
    145.         public DriveDectctorEventArgs(string drive)  
    146.         {  
    147.             Drive = drive ?? string.Empty;  
    148.         }  
    149.     }  
    150.     #region Win32 API   
    151.     public partial class NativeConstants  
    152.     {  
    153.         /// WM_DEVICECHANGE -> 0x0219   
    154.         public const int WM_DEVICECHANGE = 537;  
    155.         /// BROADCAST_QUERY_DENY -> 0x424D5144   
    156.         //public const int BROADCAST_QUERY_DENY = 1112363332;   
    157.         //public const int DBT_DEVTYP_DEVICEINTERFACE = 5;   
    158.         //public const int DBT_DEVTYP_HANDLE = 6;   
    159.         public const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device   
    160.         //public const int DBT_DEVICEQUERYREMOVE = 0x8001;   // Preparing to remove (any program can disable the removal)   
    161.         public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // removed    
    162.         public const int DBT_DEVTYP_VOLUME = 0x00000002; // drive type is logical volume   
    163.     }  
    164.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]  
    165.     public struct DEV_BROADCAST_VOLUME  
    166.     {  
    167.         /// DWORD->unsigned int   
    168.         public uint dbcv_size;  
    169.         /// DWORD->unsigned int   
    170.         public uint dbcv_devicetype;  
    171.         /// DWORD->unsigned int   
    172.         public uint dbcv_reserved;  
    173.         /// DWORD->unsigned int   
    174.         public uint dbcv_unitmask;  
    175.         /// WORD->unsigned short   
    176.         public ushort dbcv_flags;  
    177.     }  
    178.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]  
    179.     public struct OVERLAPPED  
    180.     {  
    181.         /// ULONG_PTR->unsigned int   
    182.         public uint Internal;  
    183.         /// ULONG_PTR->unsigned int   
    184.         public uint InternalHigh;  
    185.         /// Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196   
    186.         public Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196 Union1;  
    187.         /// HANDLE->void*   
    188.         public System.IntPtr hEvent;  
    189.     }  
    190.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]  
    191.     public struct Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196  
    192.     {  
    193.         /// Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6   
    194.         [System.Runtime.InteropServices.FieldOffsetAttribute(0)]  
    195.         public Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6 Struct1;  
    196.         /// PVOID->void*   
    197.         [System.Runtime.InteropServices.FieldOffsetAttribute(0)]  
    198.         public System.IntPtr Pointer;  
    199.     }  
    200.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]  
    201.     public struct Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6  
    202.     {  
    203.         /// DWORD->unsigned int   
    204.         public uint Offset;  
    205.         /// DWORD->unsigned int   
    206.         public uint OffsetHigh;  
    207.     }  
    208.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]  
    209.     public struct SECURITY_ATTRIBUTES  
    210.     {  
    211.         /// DWORD->unsigned int   
    212.         public uint nLength;  
    213.         /// LPVOID->void*   
    214.         public System.IntPtr lpSecurityDescriptor;  
    215.         /// BOOL->int   
    216.         [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]  
    217.         public bool bInheritHandle;  
    218.     }  
    219.     #endregion   
    220. }  

    现在,你可以在你的UI线程上创建一个DriveDetector对象,监听DeviceArrived和DeviceRemoved事件。

    然后通过该对象WndProc方法,传递UI线程上的消息。WPF程序可以直接用HwndSource对象AddHook,此方法的签名

    与HwndSourceHook委托相同。WinForm程序也没关系,override窗口的void WndProc(ref Message m)方法,按

    DriveDetector对象的WndProc签名格式,将m数据传入,或者干脆自己写个WinForm版本的。

    我的演示代码效果图如下:(注,上述代码未提供显示代码,请自己编写)

    另外,关于磁盘容量的监视可以使用FileSystemWatcher对象。

    请参考:http://msdn.microsoft.com/zh-cn/library/cc437966.aspx

    摘取代码如下:

    1. using System;  
    2. using System.IO;  
    3. using System.Security.Permissions;  
    4. public class Watcher  
    5. {  
    6.     public static void Main()  
    7.     {  
    8.         Run();  
    9.     }  
    10.     [PermissionSet(SecurityAction.Demand, Name="FullTrust")]  
    11.     public static void Run()  
    12.     {  
    13.         string[] args = System.Environment.GetCommandLineArgs();  
    14.         // If a directory is not specified, exit program.   
    15.         if(args.Length != 2)  
    16.         {  
    17.             // Display the proper way to call the program.   
    18.             Console.WriteLine("Usage: Watcher.exe (directory)");  
    19.             return;  
    20.         }  
    21.         // Create a new FileSystemWatcher and set its properties.   
    22.         FileSystemWatcher watcher = new FileSystemWatcher();  
    23.         watcher.Path = args[1];  
    24.         /* Watch for changes in LastAccess and LastWrite times, and 
    25.            the renaming of files or directories. */  
    26.         watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite  
    27.            | NotifyFilters.FileName | NotifyFilters.DirectoryName;  
    28.         // Only watch text files.   
    29.         //watcher.Filter = "*.txt";   
    30.         watcher.IncludeSubdirectories=true;  
    31.         // Add event handlers.   
    32.         watcher.Changed += new FileSystemEventHandler(OnChanged);  
    33.         watcher.Created += new FileSystemEventHandler(OnChanged);  
    34.         watcher.Deleted += new FileSystemEventHandler(OnChanged);  
    35.         watcher.Renamed += new RenamedEventHandler(OnRenamed);  
    36.         // Begin watching.   
    37.         watcher.EnableRaisingEvents = true;  
    38.         // Wait for the user to quit the program.   
    39.         Console.WriteLine("Press /'q/' to quit the sample.");  
    40.         while(Console.Read()!='q');  
    41.     }  
    42.     // Define the event handlers.   
    43.     private static void OnChanged(object source, FileSystemEventArgs e)  
    44.     {  
    45.         // Specify what is done when a file is changed, created, or deleted.   
    46.        Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);  
    47.     }  
    48.     private static void OnRenamed(object source, RenamedEventArgs e)  
    49.     {  
    50.         // Specify what is done when a file is renamed.   
    51.         Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);  
    52.     }  
    53. }  

    二、软件弹出可移动媒体

    网上有一部分关于这方法的代码,我的代码是从MSDN获取的VC++版本,需要调用多个API函数,转换为C#代码如下:

    参考:http://support.microsoft.com/kb/165721

    1. using System;  
    2. using System.Runtime.InteropServices;  
    3. using System.Threading;  
    4. /// <summary>   
    5. /// 弹出可移动媒体   
    6. /// </summary>   
    7. /// <see cref="http://support.microsoft.com/kb/165721"/>   
    8. public static class Eject  
    9. {  
    10.     private static void ReportError(string szMsg)  
    11.     {  
    12.         const string szErrorFormat = "Error {0}: {1}";  
    13.         var error = string.Format(szErrorFormat, GetLastError(), szMsg);  
    14.         Console.Error.WriteLine(error);  
    15.     }  
    16.     private static IntPtr OpenVolume(char driveLetter)  
    17.     {  
    18.         const string volumeFormat = "////.//{0}:";  
    19.         const string rootFormat = "{0}://";  
    20.         int accessFlags;  
    21.         var rootName = string.Format(rootFormat, driveLetter);  
    22.         var driveType = GetDriveTypeW(rootName);  
    23.         switch (driveType)  
    24.         {  
    25.             case DRIVE_REMOVABLE:  
    26.                 accessFlags = GENERIC_READ | GENERIC_WRITE;  
    27.                 break;  
    28.             case DRIVE_CDROM:  
    29.                 accessFlags = GENERIC_READ;  
    30.                 break;  
    31.             default:  
    32.                 Console.Error.WriteLine("Cannot eject. Drive type is incorrect.");  
    33.                 return new IntPtr(INVALID_HANDLE_VALUE);  
    34.         }  
    35.         var volumeName = string.Format(volumeFormat, driveLetter);  
    36.         var hVolume = CreateFileW(  
    37.             volumeName,  
    38.             accessFlags,  
    39.             FILE_SHARE_READ | FILE_SHARE_WRITE,  
    40.             IntPtr.Zero,  
    41.             OPEN_EXISTING,  
    42.             0,  
    43.             IntPtr.Zero);  
    44.         if (hVolume == new IntPtr(INVALID_HANDLE_VALUE))  
    45.             ReportError("CreateFile");  
    46.         return hVolume;  
    47.     }  
    48.     private static bool CloseVolume(IntPtr hVolume)  
    49.     {  
    50.         return CloseHandle(hVolume);  
    51.     }  
    52.     private static bool LockVolume(IntPtr hVolume)  
    53.     {  
    54.         const int LOCK_TIMEOUT = 10000; //10 Seconds   
    55.         const int LOCK_RETRIES = 20;  
    56.         var sleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;  
    57.         //Do this in a loop until a timeout period has expired   
    58.         for (int tryCount = 0; tryCount < LOCK_RETRIES; tryCount++)  
    59.         {  
    60.             int dwBytesReturned;  
    61.             if (DeviceIoControl(  
    62.                 hVolume,  
    63.                 FSCTL_LOCK_VOLUME,  
    64.                 IntPtr.Zero, 0,  
    65.                 IntPtr.Zero, 0,  
    66.                 out dwBytesReturned,  
    67.                 IntPtr.Zero))  
    68.                 return true; //return   
    69.             Thread.Sleep(sleepAmount);  
    70.         }  
    71.         return false;  
    72.     }  
    73.     private static bool DismountVolume(IntPtr hVolume)  
    74.     {  
    75.         int dwBytesReturned;  
    76.         return DeviceIoControl(  
    77.             hVolume,  
    78.             FSCTL_DISMOUNT_VOLUME,  
    79.             IntPtr.Zero, 0,  
    80.             IntPtr.Zero, 0,  
    81.             out dwBytesReturned,  
    82.             IntPtr.Zero);  
    83.     }  
    84.     private static bool PresentRemovalOfVolume(IntPtr hVolume,bool preventRemoval)  
    85.     {  
    86.         PREVENT_MEDIA_REMOVAL pmrBuffer;  
    87.         pmrBuffer.PreventMediaRemoval = preventRemoval;  
    88.           
    89.         var size = Marshal.SizeOf(pmrBuffer);  
    90.         IntPtr ptr = Marshal.AllocHGlobal(size);  
    91.         try  
    92.         {  
    93.             Marshal.StructureToPtr(pmrBuffer, ptr, false);  
    94.             int dwBytesReturned;  
    95.             return DeviceIoControl(  
    96.                 hVolume,  
    97.                 IOCTL_STORAGE_MEDIA_REMOVAL,  
    98.                 ptr, (uint) size,  
    99.                 IntPtr.Zero, 0,  
    100.                 out dwBytesReturned,  
    101.                 IntPtr.Zero  
    102.                 );  
    103.         }  
    104.         finally  
    105.         {  
    106.             Marshal.DestroyStructure(ptr, pmrBuffer.GetType());  
    107.         }  
    108.     }  
    109.     private static bool AutoEjectVolume(IntPtr hVolume)  
    110.     {  
    111.         int dwBytesReturned;  
    112.         return DeviceIoControl(  
    113.             hVolume,  
    114.             IOCTL_STORAGE_EJECT_MEDIA,  
    115.             IntPtr.Zero, 0,  
    116.             IntPtr.Zero, 0,  
    117.             out dwBytesReturned,  
    118.             IntPtr.Zero);  
    119.     }  
    120.     private static bool RemoveVolumeDefinition(string deviceName)  
    121.     {  
    122.         return DefineDosDeviceW(DDD_REMOVE_DEFINITION, deviceName, null);  
    123.     }  
    124.       
    125.     public static bool EjectVolume(char driveLetter, bool removeVolumeDefinition)  
    126.     {  
    127.         var removeSafely = false;  
    128.         var autoEject = false;  
    129.         //Open the volume.   
    130.         var hVolume = OpenVolume(driveLetter);  
    131.         if (hVolume == new IntPtr(INVALID_HANDLE_VALUE))  
    132.             return false;  
    133.         //Lock and dismount the volume.   
    134.         if(LockVolume(hVolume)&&DismountVolume(hVolume))  
    135.         {  
    136.             removeSafely = true;  
    137.             //Set prevent removal to false and eject the volume.   
    138.             if (PresentRemovalOfVolume(hVolume, false) && AutoEjectVolume(hVolume))  
    139.                 autoEject = true;  
    140.         }  
    141.         //Close the volume so other processes can use the drive.   
    142.         if (!CloseVolume(hVolume))  
    143.             return false;  
    144.         if(autoEject)  
    145.         {  
    146.             Console.Out.WriteLine("Media in Drive {0} has been ejected safely.",driveLetter);  
    147.         }  
    148.         else  
    149.         {  
    150.             if (removeSafely)  
    151.             {  
    152.                 Console.Out.WriteLine("Media in Drive {0} can be safely removed.", driveLetter);  
    153.             }  
    154.             else  
    155.             {  
    156.                 Console.Error.WriteLine("Media in Drive {0} is working, and can't be safely removed.", driveLetter);  
    157.                 return false;  
    158.             }  
    159.         }  
    160.         if(removeVolumeDefinition) RemoveVolumeDefinition(string.Format("{0}:", driveLetter));  
    161.         return true;  
    162.     }  
    163.     public static void Usage()  
    164.     {  
    165.         Console.Out.WriteLine("Usage: Eject <drive letter>");  
    166.         Console.Out.WriteLine();  
    167.     }  
    168.     static void Main(string[] args)  
    169.     {  
    170.         if(args.Length != 1)  
    171.         {  
    172.             Usage();  
    173.             return;  
    174.         }  
    175.           
    176.         if(!EjectVolume(args[0][0], true))  
    177.         {  
    178.             Console.Error.WriteLine("Failure ejecting drive {0}.",args[0][0]);  
    179.         }  
    180.     }  
    181.     #region WIN32 API   
    182.     /// Return Type: DWORD->unsigned int   
    183.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetLastError")]  
    184.     public static extern uint GetLastError();  
    185.     /// Return Type: UINT->unsigned int   
    186.     ///lpRootPathName: LPCWSTR->WCHAR*   
    187.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetDriveTypeW")]  
    188.     public static extern uint GetDriveTypeW([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpRootPathName);  
    189.     /// Return Type: HANDLE->void*   
    190.     ///lpFileName: LPCWSTR->WCHAR*   
    191.     ///dwDesiredAccess: DWORD->unsigned int   
    192.     ///dwShareMode: DWORD->unsigned int   
    193.     ///lpSecurityAttributes: LPSECURITY_ATTRIBUTES->_SECURITY_ATTRIBUTES*   
    194.     ///dwCreationDisposition: DWORD->unsigned int   
    195.     ///dwFlagsAndAttributes: DWORD->unsigned int   
    196.     ///hTemplateFile: HANDLE->void*   
    197.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "CreateFileW")]  
    198.     public static extern System.IntPtr CreateFileW([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpFileName, int dwDesiredAccess, uint dwShareMode, [System.Runtime.InteropServices.InAttribute()] System.IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, [System.Runtime.InteropServices.InAttribute()] System.IntPtr hTemplateFile);  
    199.     /// Return Type: BOOL->int   
    200.     ///hObject: HANDLE->void*   
    201.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "CloseHandle")]  
    202.     [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]  
    203.     public static extern bool CloseHandle([System.Runtime.InteropServices.InAttribute()] System.IntPtr hObject);  
    204.     /// Return Type: BOOL->int   
    205.     ///hDevice: HANDLE->void*   
    206.     ///dwIoControlCode: DWORD->unsigned int   
    207.     ///lpInBuffer: LPVOID->void*   
    208.     ///nInBufferSize: DWORD->unsigned int   
    209.     ///lpOutBuffer: LPVOID->void*   
    210.     ///nOutBufferSize: DWORD->unsigned int   
    211.     ///lpBytesReturned: LPDWORD->DWORD*   
    212.     ///lpOverlapped: LPOVERLAPPED->_OVERLAPPED*   
    213.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "DeviceIoControl")]  
    214.     [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]  
    215.     public static extern bool DeviceIoControl([System.Runtime.InteropServices.InAttribute()] System.IntPtr hDevice, uint dwIoControlCode, [System.Runtime.InteropServices.InAttribute()] System.IntPtr lpInBuffer, uint nInBufferSize, System.IntPtr lpOutBuffer, uint nOutBufferSize, out int lpBytesReturned, System.IntPtr lpOverlapped);  
    216.   
    217.     /// DRIVE_REMOVABLE -> 2   
    218.     public const int DRIVE_REMOVABLE = 2;  
    219.     /// DRIVE_CDROM -> 5   
    220.     public const int DRIVE_CDROM = 5;  
    221.     /// INVALID_HANDLE_VALUE -> -1   
    222.     public const int INVALID_HANDLE_VALUE = -1;  
    223.     /// GENERIC_READ -> (0x80000000L)   
    224.     public const int GENERIC_READ = -2147483648;  
    225.     /// GENERIC_WRITE -> (0x40000000L)   
    226.     public const int GENERIC_WRITE = 1073741824;  
    227.     /// FILE_SHARE_READ -> 0x00000001   
    228.     public const int FILE_SHARE_READ = 1;  
    229.     /// FILE_SHARE_WRITE -> 0x00000002   
    230.     public const int FILE_SHARE_WRITE = 2;  
    231.     /// OPEN_EXISTING -> 3   
    232.     public const int OPEN_EXISTING = 3;  
    233.     //WinIoCtl.h   
    234.     //   
    235.     //#define CTL_CODE( DeviceType, Function, Method, Access ) (                 /   
    236.     //  ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) /   
    237.     //)   
    238.     private const int FILE_DEVICE_FILE_SYSTEM = 0x00000009;  
    239.     private const int METHOD_BUFFERED = 0;  
    240.     private const int FILE_ANY_ACCESS = 0;  
    241.     //#define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  6, METHOD_BUFFERED, FILE_ANY_ACCESS)   
    242.     public const int FSCTL_LOCK_VOLUME = ((FILE_DEVICE_FILE_SYSTEM) << 16) | ((FILE_ANY_ACCESS) << 14) | ((6) << 2) | (METHOD_BUFFERED);  
    243.     public const int FSCTL_UNLOCK_VOLUME = ((FILE_DEVICE_FILE_SYSTEM) << 16) | ((FILE_ANY_ACCESS) << 14) | ((7) << 2) | (METHOD_BUFFERED);  
    244.     public const int FSCTL_DISMOUNT_VOLUME = ((FILE_DEVICE_FILE_SYSTEM) << 16) | ((FILE_ANY_ACCESS) << 14) | ((8) << 2) | (METHOD_BUFFERED);  
    245.     //#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE   
    246.     private const int FILE_DEVICE_MASS_STORAGE = 0x0000002d;  
    247.     private const int IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;  
    248.     //#define FILE_READ_ACCESS          ( 0x0001 )    // file & pipe   
    249.     private const int FILE_READ_ACCESS = 0x0001;  
    250.       
    251.     //#define IOCTL_STORAGE_MEDIA_REMOVAL           CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)   
    252.     public const int IOCTL_STORAGE_MEDIA_REMOVAL =  
    253.         ((IOCTL_STORAGE_BASE) << 16) | ((FILE_READ_ACCESS) << 14) | ((0x0201) << 2) | (METHOD_BUFFERED);  
    254.     //#define IOCTL_STORAGE_EJECT_MEDIA             CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)   
    255.     public const int IOCTL_STORAGE_EJECT_MEDIA =  
    256.         ((IOCTL_STORAGE_BASE) << 16) | ((FILE_READ_ACCESS) << 14) | ((0x0202) << 2) | (METHOD_BUFFERED);  
    257.   
    258.     [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]  
    259.     public struct PREVENT_MEDIA_REMOVAL  
    260.     {  
    261.         /// BOOLEAN->BYTE->unsigned char   
    262.         [MarshalAs(UnmanagedType.I1)]  
    263.         public bool PreventMediaRemoval;  
    264.     }  
    265.      
    266.     #region Remove Volume Definition   
    267.     /// DDD_REMOVE_DEFINITION -> 0x00000002   
    268.     public const int DDD_REMOVE_DEFINITION = 2;  
    269.           
    270.     /// Return Type: BOOL->int   
    271.     ///dwFlags: DWORD->unsigned int   
    272.     ///lpDeviceName: LPCWSTR->WCHAR*   
    273.     ///lpTargetPath: LPCWSTR->WCHAR*   
    274.     [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="DefineDosDeviceW")]  
    275.     [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]  
    276.     public static extern  bool DefineDosDeviceW(uint dwFlags, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpDeviceName, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpTargetPath) ;  
    277.     #endregion  
    278.      
    279.     #endregion   
    280. }  

    预览:(注,弹出可移动磁盘,并不会删除驱动器号,但设备已经被弹出,如图中的h盘)

    注:已改进,安全弹出后,通过DDD_REMOVE_DEFINITION移除h盘。

  • 相关阅读:
    Objective-C ,ios,iphone开发基础:ios数据库(The SQLite Database),使用终端进行简单的数据库操作
    Objective-C ,ios,iphone开发基础:picker控件详解与使用,(实现省市的二级联动)
    Objective-C ,ios,iphone开发基础:多个视图(view)之间的切换2,使用导航栏控制,以及视图之间传值。
    Objective-C ,ios,iphone开发基础:多个视图(view)之间的切换,以及视图之间传值。
    Objective-C ,ios,iphone开发基础:NSDictionary(字典) 和 NSMutableDictionary
    Objective-C ,ios,iphone开发基础:几个常用类-NSString
    为MYPoint类写一个分类
    使用copy再次实现Circle类,保证不能有内存泄漏问题
    实现Square类,让其继承自Rectangle类,并在Square类增添新属性和方法,在2的基础上,在Square类中重写Rectangle类中的初始化和打印方法
    实现Square类,让其继承自Rectangle类,并在Square类增添新属性和方法
  • 原文地址:https://www.cnblogs.com/soundcode/p/9376864.html
Copyright © 2020-2023  润新知