USB设备的插入和弹出的监听以及软弹出可移动媒体(如Windows的移除USB设备) .
一、监听USB设备的插入和弹出
当USB设备插入或者弹出时,Windows会产生一条全局消息:WM_DEVICECHANGE
我们需要做的是,获得这条消息的wParam参数,如果为DBT_DEVICEARRIVAL则表示有设备插入并可用,
如果是DBT_DEVICEREMOVECOMPLETE则表示有设备已经移除。再查看lParam参数为DBT_DEVTYP_VOLUME时,
就可以取出DEV_BROADCAST_VOLUME结构的卷号dbcv_unitmask,就知道是哪个卷被插入或者弹出。
代码片段如下:
- using System;
- using System.Runtime.InteropServices;
- /// <summary>
- /// 监听设备的插入和拔出
- /// </summary>
- public class DriveDetector
- {
- /// <summary>
- /// 设备插入事件
- /// </summary>
- public event EventHandler<DriveDectctorEventArgs> DeviceArrived = null;
- /// <summary>
- /// 设备拔出事件
- /// </summary>
- public event EventHandler<DriveDectctorEventArgs> DeviceRemoved = null;
- /// <summary>
- /// 消息处理(HwndSourceHook委托的签名)
- /// </summary>
- /// <param name="hwnd"></param>
- /// <param name="msg"></param>
- /// <param name="wParam"></param>
- /// <param name="lParam"></param>
- /// <param name="handled"></param>
- /// <returns></returns>
- 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);
- }
- /// <summary>
- /// 获得盘符
- /// </summary>
- /// <param name="dbcvUnitmask">
- /// 1 = A
- /// 2 = B
- /// 4 = C...
- /// </param>
- /// <returns>结果是A~Z的任意一个字符或者为'?'</returns>
- 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;
- }
- /*
- private static void GetLetterTest()
- {
- for (int i = 0; i < 67108864; i++)
- {
- Console.WriteLine("{0} - {1}", i, GetLetter((uint)i));
- i = i << 1;
- }
- //0 - ?
- //1 - A
- //3 - B
- //7 - C
- //15 - D
- //31 - E
- //63 - F
- //127 - G
- //255 - H
- //511 - I
- //1023 - J
- //2047 - K
- //4095 - L
- //8191 - M
- //16383 - N
- //32767 - O
- //65535 - P
- //131071 - Q
- //262143 - R
- //524287 - S
- //1048575 - T
- //2097151 - U
- //4194303 - V
- //8388607 - W
- //16777215 - X
- //33554431 - Y
- //67108863 - Z
- }*/
- /// <summary>
- /// 设备插入或拔出事件
- /// </summary>
- public class DriveDectctorEventArgs : EventArgs
- {
- /// <summary>
- /// 获得设备卷标
- /// </summary>
- public string Drive { get; private set; }
- public DriveDectctorEventArgs(string drive)
- {
- Drive = drive ?? string.Empty;
- }
- }
- #region Win32 API
- public partial class NativeConstants
- {
- /// WM_DEVICECHANGE -> 0x0219
- public const int WM_DEVICECHANGE = 537;
- /// BROADCAST_QUERY_DENY -> 0x424D5144
- //public const int BROADCAST_QUERY_DENY = 1112363332;
- //public const int DBT_DEVTYP_DEVICEINTERFACE = 5;
- //public const int DBT_DEVTYP_HANDLE = 6;
- public const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device
- //public const int DBT_DEVICEQUERYREMOVE = 0x8001; // Preparing to remove (any program can disable the removal)
- public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // removed
- public const int DBT_DEVTYP_VOLUME = 0x00000002; // drive type is logical volume
- }
- [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
- public struct DEV_BROADCAST_VOLUME
- {
- /// DWORD->unsigned int
- public uint dbcv_size;
- /// DWORD->unsigned int
- public uint dbcv_devicetype;
- /// DWORD->unsigned int
- public uint dbcv_reserved;
- /// DWORD->unsigned int
- public uint dbcv_unitmask;
- /// WORD->unsigned short
- public ushort dbcv_flags;
- }
- [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
- public struct OVERLAPPED
- {
- /// ULONG_PTR->unsigned int
- public uint Internal;
- /// ULONG_PTR->unsigned int
- public uint InternalHigh;
- /// Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196
- public Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196 Union1;
- /// HANDLE->void*
- public System.IntPtr hEvent;
- }
- [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
- public struct Anonymous_7416d31a_1ce9_4e50_b1e1_0f2ad25c0196
- {
- /// Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6
- [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
- public Anonymous_ac6e4301_4438_458f_96dd_e86faeeca2a6 Struct1;
- /// PVOID->void*
- [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
- {
- /// DWORD->unsigned int
- public uint Offset;
- /// DWORD->unsigned int
- public uint OffsetHigh;
- }
- [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
- public struct SECURITY_ATTRIBUTES
- {
- /// DWORD->unsigned int
- public uint nLength;
- /// LPVOID->void*
- public System.IntPtr lpSecurityDescriptor;
- /// BOOL->int
- [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
摘取代码如下:
- 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 a directory is not specified, exit program.
- if(args.Length != 2)
- {
- // Display the proper way to call the program.
- Console.WriteLine("Usage: Watcher.exe (directory)");
- return;
- }
- // Create a new FileSystemWatcher and set its properties.
- FileSystemWatcher watcher = new FileSystemWatcher();
- watcher.Path = args[1];
- /* Watch for changes in LastAccess and LastWrite times, and
- the renaming of files or directories. */
- watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
- | NotifyFilters.FileName | NotifyFilters.DirectoryName;
- // Only watch text files.
- //watcher.Filter = "*.txt";
- watcher.IncludeSubdirectories=true;
- // Add event handlers.
- watcher.Changed += new FileSystemEventHandler(OnChanged);
- watcher.Created += new FileSystemEventHandler(OnChanged);
- watcher.Deleted += new FileSystemEventHandler(OnChanged);
- watcher.Renamed += new RenamedEventHandler(OnRenamed);
- // Begin watching.
- watcher.EnableRaisingEvents = true;
- // Wait for the user to quit the program.
- Console.WriteLine("Press /'q/' to quit the sample.");
- while(Console.Read()!='q');
- }
- // Define the event handlers.
- private static void OnChanged(object source, FileSystemEventArgs e)
- {
- // Specify what is done when a file is changed, created, or deleted.
- Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
- }
- private static void OnRenamed(object source, RenamedEventArgs e)
- {
- // Specify what is done when a file is renamed.
- Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
- }
- }
二、软件弹出可移动媒体
网上有一部分关于这方法的代码,我的代码是从MSDN获取的VC++版本,需要调用多个API函数,转换为C#代码如下:
参考:http://support.microsoft.com/kb/165721
- using System;
- using System.Runtime.InteropServices;
- using System.Threading;
- /// <summary>
- /// 弹出可移动媒体
- /// </summary>
- /// <see cref="http://support.microsoft.com/kb/165721"/>
- 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; //10 Seconds
- const int LOCK_RETRIES = 20;
- var sleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
- //Do this in a loop until a timeout period has expired
- 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; //return
- 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;
- //Open the volume.
- var hVolume = OpenVolume(driveLetter);
- if (hVolume == new IntPtr(INVALID_HANDLE_VALUE))
- return false;
- //Lock and dismount the volume.
- if(LockVolume(hVolume)&&DismountVolume(hVolume))
- {
- removeSafely = true;
- //Set prevent removal to false and eject the volume.
- if (PresentRemovalOfVolume(hVolume, false) && AutoEjectVolume(hVolume))
- autoEject = true;
- }
- //Close the volume so other processes can use the drive.
- 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
- /// Return Type: DWORD->unsigned int
- [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetLastError")]
- public static extern uint GetLastError();
- /// Return Type: UINT->unsigned int
- ///lpRootPathName: LPCWSTR->WCHAR*
- [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);
- /// Return Type: HANDLE->void*
- ///lpFileName: LPCWSTR->WCHAR*
- ///dwDesiredAccess: DWORD->unsigned int
- ///dwShareMode: DWORD->unsigned int
- ///lpSecurityAttributes: LPSECURITY_ATTRIBUTES->_SECURITY_ATTRIBUTES*
- ///dwCreationDisposition: DWORD->unsigned int
- ///dwFlagsAndAttributes: DWORD->unsigned int
- ///hTemplateFile: HANDLE->void*
- [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);
- /// Return Type: BOOL->int
- ///hObject: HANDLE->void*
- [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);
- /// Return Type: BOOL->int
- ///hDevice: HANDLE->void*
- ///dwIoControlCode: DWORD->unsigned int
- ///lpInBuffer: LPVOID->void*
- ///nInBufferSize: DWORD->unsigned int
- ///lpOutBuffer: LPVOID->void*
- ///nOutBufferSize: DWORD->unsigned int
- ///lpBytesReturned: LPDWORD->DWORD*
- ///lpOverlapped: LPOVERLAPPED->_OVERLAPPED*
- [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);
- /// DRIVE_REMOVABLE -> 2
- public const int DRIVE_REMOVABLE = 2;
- /// DRIVE_CDROM -> 5
- public const int DRIVE_CDROM = 5;
- /// INVALID_HANDLE_VALUE -> -1
- public const int INVALID_HANDLE_VALUE = -1;
- /// GENERIC_READ -> (0x80000000L)
- public const int GENERIC_READ = -2147483648;
- /// GENERIC_WRITE -> (0x40000000L)
- public const int GENERIC_WRITE = 1073741824;
- /// FILE_SHARE_READ -> 0x00000001
- public const int FILE_SHARE_READ = 1;
- /// FILE_SHARE_WRITE -> 0x00000002
- public const int FILE_SHARE_WRITE = 2;
- /// OPEN_EXISTING -> 3
- public const int OPEN_EXISTING = 3;
- //WinIoCtl.h
- //
- //#define CTL_CODE( DeviceType, Function, Method, Access ) ( /
- // ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) /
- //)
- private const int FILE_DEVICE_FILE_SYSTEM = 0x00000009;
- private const int METHOD_BUFFERED = 0;
- private const int FILE_ANY_ACCESS = 0;
- //#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
- 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);
- //#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
- private const int FILE_DEVICE_MASS_STORAGE = 0x0000002d;
- private const int IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
- //#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe
- private const int FILE_READ_ACCESS = 0x0001;
- //#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
- public const int IOCTL_STORAGE_MEDIA_REMOVAL =
- ((IOCTL_STORAGE_BASE) << 16) | ((FILE_READ_ACCESS) << 14) | ((0x0201) << 2) | (METHOD_BUFFERED);
- //#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
- 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
- {
- /// BOOLEAN->BYTE->unsigned char
- [MarshalAs(UnmanagedType.I1)]
- public bool PreventMediaRemoval;
- }
- #region Remove Volume Definition
- /// DDD_REMOVE_DEFINITION -> 0x00000002
- public const int DDD_REMOVE_DEFINITION = 2;
- /// Return Type: BOOL->int
- ///dwFlags: DWORD->unsigned int
- ///lpDeviceName: LPCWSTR->WCHAR*
- ///lpTargetPath: LPCWSTR->WCHAR*
- [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设备) .的更多相关文章
- layui 弹出层监听 判断弹出框的大小
if ($.PublicIsMobile($(window).width())) { var layerInitWidth = $("#layui-layer" + ly_dtxm ...
- android软键盘弹出隐藏的监听
通过网上搜索关于软键盘的隐藏弹出的监听,有几种方式,其中最有效的方式是在View的Onlayout()里面做文章 具体代码: 将布局视图自定义,重写onlayout()方法,然后在主Activity里 ...
- 与众不同 windows phone (21) - Device(设备)之摄像头(拍摄照片, 录制视频)
原文:与众不同 windows phone (21) - Device(设备)之摄像头(拍摄照片, 录制视频) [索引页][源码下载] 与众不同 windows phone (21) - Device ...
- c# 获取移动硬盘信息、监听移动设备的弹出与插入事件
原文 http://www.cnblogs.com/coolkiss/p/3328825.html 备忘一下改功能,主要通过WMI来实现,对于监听外接设备的弹出和插入事件一开始使用IntPtr Wnd ...
- I.MX6 简单电路模拟USB设备的插入
/**************************************************************************** * I.MX6 简单电路模拟USB设备的插入 ...
- Android监听自身卸载,弹出用户反馈调查
1,情景分析 在上上篇博客中我写了一下NDK开发实践项目,使用开源的LAME库转码MP3,作为前面几篇基础博客的加深理解使用的,但是这样的项目用处不大,除了练练NDK功底.这篇博客,我将讲述一下一个各 ...
- Android 应用监听自身卸载,弹出用户反馈调查
监听卸载情景和原理分析 1,情景分析 在上上篇博客中我写了一下NDK开发实践项目,使用开源的LAME库转码MP3,作为前面几篇基础博客的加深理解使用的,但是这样的项目用处不大,除了练练NDK功底.这篇 ...
- Windows电脑无法识别USB设备怎么办?
您可能已经注意到,如果您使用USB设备并将其插入计算机,Windows会识别并配置它.然后,如果你拔掉它并将其重新插入另一个USB端口,Windows就会出现一连串的健忘症,并认为这是一个完全不同的设 ...
- Android 另类方法监听软键盘的弹出收起事件
http://www.cnblogs.com/csonezp/p/5065624.html 最近做的项目碰到个问题,a界面是fragment+recyclerview,b界面带个edittext,并且 ...
随机推荐
- tensorflow随机张量创建
TensorFlow 有几个操作用来创建不同分布的随机张量.注意随机操作是有状态的,并在每次评估时创建新的随机值. 下面是一些相关的函数的介绍: tf.random_normal 从正态分布中输出随机 ...
- 分模块开发创建Action子模块——(九)
web层选择war打包方式. 1.右击父工程新建maven模块
- 【干货】已Window7 系统为例,谈谈boot引导程序-------附带看看数据隐藏
来源:Unit 3: Unix/Linux File System 3.1 Unix/Linux File System Booting Process 使用工具:EnCase Forensic 学习 ...
- node.js 安装 测试
2014年5月1日 18:48:01 安装: 系统是centos,里边的python版本是2.4,但是node.js 源码tar包安装要求是 2.6 或者 2.7 下载python 2.7编译安装,注 ...
- 解决Spring配置文件不显示design和source, namespace 问题
之前撸代码一直没太关注这个问题,后来发现对于不太熟悉配置文件内容的小伙伴们来说是比较痛苦的,因为每个配置项都需要你记住或者拷贝别人现成配置 那么问题来了,今天在写发现我的Spring配置文件不显示de ...
- 压缩跟踪Compressive Tracking(转)
这位博主总结的实在太好了,从原理到论文到代码,连论文都不用看:论文:http://blog.csdn.net/zouxy09/article/details/8118360 代码部分:http://b ...
- .NetCore 利用Jenkins在 Windows平台下打包发布Angular项目
准备环境 安装Jenkins 首先装node,版本根据实际环境而定(node安装包中包含了npm) 安装一般都配置好了环境变量,检查下如果没有就配置下 Jenkins中安装NPM插件 GIt获取代码 ...
- Java ArrayList中对象的排序 (Comparable VS Comparator)
我们通常使用Collections.sort()方法来对一个简单的数据列表排序.但是当ArrayList是由自定义对象组成的,就需要使用comparable或者comparator接口了.在使用这两者 ...
- [转] javascript组件开发方式
作为一名前端工程师,写组件的能力至关重要.虽然JavaScript经常被人嘲笑是个小玩具,但是在一代代大牛的前仆后继的努力下,渐渐的也摸索了一套组件的编写方式. 下面我们来谈谈,在现有的知识体系下,如 ...
- JS跨域设置和取Cookie
在Javascript脚本里,一个cookie 实际就是一个字符串属性.当你读取cookie的值时,就得到一个字符串,里面当前WEB页使用的所有cookies的名称和值.每个cookie除了 name ...