一、監聽USB設備的插入和彈出
當USB設備插入或者彈出時,Windows會產生一條全局消息:WM_DEVICECHANGE
我們需要做的是,獲得這條消息的wParam參數,如果為DBT_DEVICEARRIVAL則表示有設備插入并可用,
如果是DBT_DEVICEREMOVECOMPLETE則表示有設備已經移除。再查看lParam參數為DBT_DEVTYP_VOLUME時,
就可以取出DEV_BROADCAST_VOLUME結構的卷號dbcv_unitmask,就知道是哪個卷被插入或者彈出。
代碼片段如下:
[c-sharp]?view plaincopyprint?
using?System;??using?System.Runtime.InteropServices;??public?class?DriveDetector??{??????????????????public?event?EventHandler<DriveDectctorEventArgs>?DeviceArrived?=?null;??????????????????public?event?EventHandler<DriveDectctorEventArgs>?DeviceRemoved?=?null;??????????????????????????????????????????public?IntPtr?WndProc(??????????IntPtr?hwnd,??????????int?msg,??????????IntPtr?wParam,??????????IntPtr?lParam,??????????ref?bool?handled)??????{??????????if?(msg?==?NativeConstants.WM_DEVICECHANGE)??????????{??#warning?USB設備檢測目前只支持32位系統)???????????????switch?(wParam.ToInt32())??????????????{??????????????????case?NativeConstants.DBT_DEVICEARRIVAL:??????????????????????{??????????????????????????var?devType?=?Marshal.ReadInt32(lParam,?4);??????????????????????????if?(devType?==?NativeConstants.DBT_DEVTYP_VOLUME)??????????????????????????{??????????????????????????????var?drive?=?GetDrive(lParam);??????????????????????????????if?(DeviceArrived?!=?null)??????????????????????????????{??????????????????????????????????var?args?=?new?DriveDectctorEventArgs(drive);??????????????????????????????????DeviceArrived(this,?args);?????????????????????????????}??????????????????????????}??????????????????????}??????????????????????break;??????????????????case?NativeConstants.DBT_DEVICEREMOVECOMPLETE:??????????????????????{??????????????????????????var?devType?=?Marshal.ReadInt32(lParam,?4);??????????????????????????if?(devType?==?NativeConstants.DBT_DEVTYP_VOLUME)??????????????????????????{??????????????????????????????var?drive?=?GetDrive(lParam);??????????????????????????????if?(DeviceRemoved?!=?null)??????????????????????????????{??????????????????????????????????var?args?=?new?DriveDectctorEventArgs(drive);??????????????????????????????????DeviceRemoved(this,?args);??????????????????????????????}??????????????????????????}??????????????????????}??????????????????????break;??????????????}??????????}??????????return?IntPtr.Zero;??????}??????private?static?string?GetDrive(IntPtr?lParam)??????{??????????var?volume?=?(DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(lParam,?typeof(DEV_BROADCAST_VOLUME));??????????var?letter?=?GetLetter(volume.dbcv_unitmask);??????????return?string.Format("{0}://",?letter);??????}??????????????????????????????????????????private?static?char?GetLetter(uint?dbcvUnitmask)??????{??????????const?char?nona?=?'?';??????????const?string?drives?=?"ABCDEFGHIJKLMNOPQRSTUVWXYZ";??????????if?(dbcvUnitmask?==?0)?return?nona;??????????var?i?=?0;??????????var?pom?=?dbcvUnitmask?>>?1;??????????while?(pom?!=?0)??????????{??????????????pom?=?pom?>>?1;??????????????i++;??????????}??????????if?(i?<?drives.Length)??????????????return?drives[i];??????????return?nona;??????}??????????????????????public?class?DriveDectctorEventArgs?:?EventArgs??????{??????????????????????????????????public?string?Drive?{?get;?private?set;?}??????????public?DriveDectctorEventArgs(string?drive)??????????{??????????????Drive?=?drive????string.Empty;??????????}??????}??????#region?Win32?API???????public?partial?class?NativeConstants??????{??????????????????public?const?int?WM_DEVICECHANGE?=?537;??????????????????????????????????????????public?const?int?DBT_DEVICEARRIVAL?=?0x8000;?????????????????public?const?int?DBT_DEVICEREMOVECOMPLETE?=?0x8004;?????????public?const?int?DBT_DEVTYP_VOLUME?=?0x00000002;?????}??????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]??????public?struct?DEV_BROADCAST_VOLUME??????{??????????????????public?uint?dbcv_size;??????????????????public?uint?dbcv_devicetype;??????????????????public?uint?dbcv_reserved;??????????????????public?uint?dbcv_unitmask;??????????????????public?ushort?dbcv_flags;??????}??????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]??????public?struct?OVERLAPPED??????{??????????????????public?uint?Internal;??????????????????public?uint?InternalHigh;??????????????????public?Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196?Union1;??????????????????public?System.IntPtr?hEvent;??????}??????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]??????public?struct?Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196??????{??????????????????[System.Runtime.InteropServices.FieldOffsetAttribute(0)]??????????public?Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6?Struct1;??????????????????[System.Runtime.InteropServices.FieldOffsetAttribute(0)]??????????public?System.IntPtr?Pointer;??????}??????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]??????public?struct?Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6??????{??????????????????public?uint?Offset;??????????????????public?uint?OffsetHigh;??????}??????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]??????public?struct?SECURITY_ATTRIBUTES??????{??????????????????public?uint?nLength;??????????????????public?System.IntPtr?lpSecurityDescriptor;??????????????????[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]??????????public?bool?bInheritHandle;??????}??????#endregion???}?? 現在,你可以在你的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
摘取代碼如下:
[c-sharp]?view plaincopyprint?
using?System;??using?System.IO;??using?System.Security.Permissions;??public?class?Watcher??{??????public?static?void?Main()??????{??????????Run();??????}??????[PermissionSet(SecurityAction.Demand,?Name="FullTrust")]??????public?static?void?Run()??????{??????????string[]?args?=?System.Environment.GetCommandLineArgs();??????????????????if(args.Length?!=?2)??????????{??????????????????????????Console.WriteLine("Usage:?Watcher.exe?(directory)");??????????????return;??????????}??????????????????FileSystemWatcher?watcher?=?new?FileSystemWatcher();??????????watcher.Path?=?args[1];??????????????????watcher.NotifyFilter?=?NotifyFilters.LastAccess?|?NotifyFilters.LastWrite?????????????|?NotifyFilters.FileName?|?NotifyFilters.DirectoryName;??????????????????????????watcher.IncludeSubdirectories=true;??????????????????watcher.Changed?+=?new?FileSystemEventHandler(OnChanged);??????????watcher.Created?+=?new?FileSystemEventHandler(OnChanged);??????????watcher.Deleted?+=?new?FileSystemEventHandler(OnChanged);??????????watcher.Renamed?+=?new?RenamedEventHandler(OnRenamed);??????????????????watcher.EnableRaisingEvents?=?true;??????????????????Console.WriteLine("Press?/'q/'?to?quit?the?sample.");??????????while(Console.Read()!='q');??????}??????????private?static?void?OnChanged(object?source,?FileSystemEventArgs?e)??????{?????????????????Console.WriteLine("File:?"?+??e.FullPath?+?"?"?+?e.ChangeType);??????}??????private?static?void?OnRenamed(object?source,?RenamedEventArgs?e)??????{??????????????????Console.WriteLine("File:?{0}?renamed?to?{1}",?e.OldFullPath,?e.FullPath);??????}??}?? 二、軟件彈出可移動媒體
網上有一部分關于這方法的代碼,我的代碼是從MSDN獲取的VC++版本,需要調用多個API函數,轉換為C#代碼如下:
參考:http://support.microsoft.com/kb/165721
[c-sharp]?view plaincopyprint?
using?System;??using?System.Runtime.InteropServices;??using?System.Threading;??public?static?class?Eject??{??????private?static?void?ReportError(string?szMsg)??????{??????????const?string?szErrorFormat?=?"Error?{0}:?{1}";??????????var?error?=?string.Format(szErrorFormat,?GetLastError(),?szMsg);??????????Console.Error.WriteLine(error);??????}??????private?static?IntPtr?OpenVolume(char?driveLetter)??????{??????????const?string?volumeFormat?=?".//{0}:";??????????const?string?rootFormat?=?"{0}://";??????????int?accessFlags;??????????var?rootName?=?string.Format(rootFormat,?driveLetter);??????????var?driveType?=?GetDriveTypeW(rootName);??????????switch?(driveType)??????????{??????????????case?DRIVE_REMOVABLE:??????????????????accessFlags?=?GENERIC_READ?|?GENERIC_WRITE;??????????????????break;??????????????case?DRIVE_CDROM:??????????????????accessFlags?=?GENERIC_READ;??????????????????break;??????????????default:??????????????????Console.Error.WriteLine("Cannot?eject.?Drive?type?is?incorrect.");??????????????????return?new?IntPtr(INVALID_HANDLE_VALUE);??????????}??????????var?volumeName?=?string.Format(volumeFormat,?driveLetter);??????????var?hVolume?=?CreateFileW(??????????????volumeName,??????????????accessFlags,??????????????FILE_SHARE_READ?|?FILE_SHARE_WRITE,??????????????IntPtr.Zero,??????????????OPEN_EXISTING,??????????????0,??????????????IntPtr.Zero);??????????if?(hVolume?==?new?IntPtr(INVALID_HANDLE_VALUE))??????????????ReportError("CreateFile");??????????return?hVolume;??????}??????private?static?bool?CloseVolume(IntPtr?hVolume)??????{??????????return?CloseHandle(hVolume);??????}??????private?static?bool?LockVolume(IntPtr?hVolume)??????{??????????const?int?LOCK_TIMEOUT?=?10000;?????????const?int?LOCK_RETRIES?=?20;??????????var?sleepAmount?=?LOCK_TIMEOUT?/?LOCK_RETRIES;??????????????????for?(int?tryCount?=?0;?tryCount?<?LOCK_RETRIES;?tryCount++)??????????{??????????????int?dwBytesReturned;??????????????if?(DeviceIoControl(??????????????????hVolume,??????????????????FSCTL_LOCK_VOLUME,??????????????????IntPtr.Zero,?0,??????????????????IntPtr.Zero,?0,??????????????????out?dwBytesReturned,??????????????????IntPtr.Zero))??????????????????return?true;?????????????Thread.Sleep(sleepAmount);??????????}??????????return?false;??????}??????private?static?bool?DismountVolume(IntPtr?hVolume)??????{??????????int?dwBytesReturned;??????????return?DeviceIoControl(??????????????hVolume,??????????????FSCTL_DISMOUNT_VOLUME,??????????????IntPtr.Zero,?0,??????????????IntPtr.Zero,?0,??????????????out?dwBytesReturned,??????????????IntPtr.Zero);??????}??????private?static?bool?PresentRemovalOfVolume(IntPtr?hVolume,bool?preventRemoval)??????{??????????PREVENT_MEDIA_REMOVAL?pmrBuffer;??????????pmrBuffer.PreventMediaRemoval?=?preventRemoval;????????????????????var?size?=?Marshal.SizeOf(pmrBuffer);??????????IntPtr?ptr?=?Marshal.AllocHGlobal(size);??????????try??????????{??????????????Marshal.StructureToPtr(pmrBuffer,?ptr,?false);??????????????int?dwBytesReturned;??????????????return?DeviceIoControl(??????????????????hVolume,??????????????????IOCTL_STORAGE_MEDIA_REMOVAL,??????????????????ptr,?(uint)?size,??????????????????IntPtr.Zero,?0,??????????????????out?dwBytesReturned,??????????????????IntPtr.Zero??????????????????);??????????}??????????finally??????????{??????????????Marshal.DestroyStructure(ptr,?pmrBuffer.GetType());??????????}??????}??????private?static?bool?AutoEjectVolume(IntPtr?hVolume)??????{??????????int?dwBytesReturned;??????????return?DeviceIoControl(??????????????hVolume,??????????????IOCTL_STORAGE_EJECT_MEDIA,??????????????IntPtr.Zero,?0,??????????????IntPtr.Zero,?0,??????????????out?dwBytesReturned,??????????????IntPtr.Zero);??????}??????private?static?bool?RemoveVolumeDefinition(string?deviceName)??????{??????????return?DefineDosDeviceW(DDD_REMOVE_DEFINITION,?deviceName,?null);??????}????????????public?static?bool?EjectVolume(char?driveLetter,?bool?removeVolumeDefinition)??????{??????????var?removeSafely?=?false;??????????var?autoEject?=?false;??????????????????var?hVolume?=?OpenVolume(driveLetter);??????????if?(hVolume?==?new?IntPtr(INVALID_HANDLE_VALUE))??????????????return?false;??????????????????if(LockVolume(hVolume)&&DismountVolume(hVolume))??????????{??????????????removeSafely?=?true;??????????????????????????if?(PresentRemovalOfVolume(hVolume,?false)?&&?AutoEjectVolume(hVolume))??????????????????autoEject?=?true;??????????}??????????????????if?(!CloseVolume(hVolume))??????????????return?false;??????????if(autoEject)??????????{??????????????Console.Out.WriteLine("Media?in?Drive?{0}?has?been?ejected?safely.",driveLetter);??????????}??????????else??????????{??????????????if?(removeSafely)??????????????{??????????????????Console.Out.WriteLine("Media?in?Drive?{0}?can?be?safely?removed.",?driveLetter);??????????????}??????????????else??????????????{??????????????????Console.Error.WriteLine("Media?in?Drive?{0}?is?working,?and?can't?be?safely?removed.",?driveLetter);??????????????????return?false;??????????????}??????????}??????????if(removeVolumeDefinition)?RemoveVolumeDefinition(string.Format("{0}:",?driveLetter));??????????return?true;??????}??????public?static?void?Usage()??????{??????????Console.Out.WriteLine("Usage:?Eject?<drive?letter>");??????????Console.Out.WriteLine();??????}??????static?void?Main(string[]?args)??????{??????????if(args.Length?!=?1)??????????{??????????????Usage();??????????????return;??????????}????????????????????if(!EjectVolume(args[0][0],?true))??????????{??????????????Console.Error.WriteLine("Failure?ejecting?drive?{0}.",args[0][0]);??????????}??????}??????#region?WIN32?API???????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint?=?"GetLastError")]??????public?static?extern?uint?GetLastError();??????????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint?=?"GetDriveTypeW")]??????public?static?extern?uint?GetDriveTypeW([System.Runtime.InteropServices.InAttribute()]?[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)]?string?lpRootPathName);??????????????????????????????????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint?=?"CreateFileW")]??????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);??????????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint?=?"CloseHandle")]??????[return:?System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]??????public?static?extern?bool?CloseHandle([System.Runtime.InteropServices.InAttribute()]?System.IntPtr?hObject);??????????????????????????????????????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint?=?"DeviceIoControl")]??????[return:?System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]??????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);????????????public?const?int?DRIVE_REMOVABLE?=?2;??????????public?const?int?DRIVE_CDROM?=?5;??????????public?const?int?INVALID_HANDLE_VALUE?=?-1;??????????public?const?int?GENERIC_READ?=?-2147483648;??????????public?const?int?GENERIC_WRITE?=?1073741824;??????????public?const?int?FILE_SHARE_READ?=?1;??????????public?const?int?FILE_SHARE_WRITE?=?2;??????????public?const?int?OPEN_EXISTING?=?3;??????????????????????????private?const?int?FILE_DEVICE_FILE_SYSTEM?=?0x00000009;??????private?const?int?METHOD_BUFFERED?=?0;??????private?const?int?FILE_ANY_ACCESS?=?0;??????????public?const?int?FSCTL_LOCK_VOLUME?=?((FILE_DEVICE_FILE_SYSTEM)?<<?16)?|?((FILE_ANY_ACCESS)?<<?14)?|?((6)?<<?2)?|?(METHOD_BUFFERED);??????public?const?int?FSCTL_UNLOCK_VOLUME?=?((FILE_DEVICE_FILE_SYSTEM)?<<?16)?|?((FILE_ANY_ACCESS)?<<?14)?|?((7)?<<?2)?|?(METHOD_BUFFERED);??????public?const?int?FSCTL_DISMOUNT_VOLUME?=?((FILE_DEVICE_FILE_SYSTEM)?<<?16)?|?((FILE_ANY_ACCESS)?<<?14)?|?((8)?<<?2)?|?(METHOD_BUFFERED);??????????private?const?int?FILE_DEVICE_MASS_STORAGE?=?0x0000002d;??????private?const?int?IOCTL_STORAGE_BASE?=?FILE_DEVICE_MASS_STORAGE;??????????private?const?int?FILE_READ_ACCESS?=?0x0001;????????????????public?const?int?IOCTL_STORAGE_MEDIA_REMOVAL?=??????????((IOCTL_STORAGE_BASE)?<<?16)?|?((FILE_READ_ACCESS)?<<?14)?|?((0x0201)?<<?2)?|?(METHOD_BUFFERED);??????????public?const?int?IOCTL_STORAGE_EJECT_MEDIA?=??????????((IOCTL_STORAGE_BASE)?<<?16)?|?((FILE_READ_ACCESS)?<<?14)?|?((0x0202)?<<?2)?|?(METHOD_BUFFERED);????????[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]??????public?struct?PREVENT_MEDIA_REMOVAL??????{??????????????????[MarshalAs(UnmanagedType.I1)]??????????public?bool?PreventMediaRemoval;??????}???????????#region?Remove?Volume?Definition???????????public?const?int?DDD_REMOVE_DEFINITION?=?2;????????????????????????????????[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",?EntryPoint="DefineDosDeviceW")]??????[return:?System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]??????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)?;??????#endregion???????????#endregion???}?? 預覽:(注,彈出可移動磁盤,并不會刪除驅動器號,但設備已經被彈出,如圖中的h盤)
注:已改進,安全彈出后,通過DDD_REMOVE_DEFINITION移除h盤。
總結
以上是生活随笔為你收集整理的USB设备的插入和弹出的监听以及软弹出可移动媒体(如Windows的移除USB设备) ....的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。