监听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);
    }
}

原文地址:http://daimajishu.iteye.com/blog/1087538
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值