监控USB的插入和拔出有几种方法,如:通过监听windows消息来获取,通过WMI查询等。
通过windows消息存在弊端就是我们的程序必须要跑在带有窗口的程序上面,另外因为操作系统不一样,消息传递的参数也不一样,所以它在不同版本的操作系统上也不一定有用,实现起来也会更麻烦。
今天介绍一下通过WMI的方式,来获取USB的插拔状态。 参加代码如下:

名称解释:WMI(Windows Management Instrumentation,Windows 管理规范)

 /// <summary>
    /// USB控制设备类型
    /// </summary>
    public struct USBControllerDevice
    {
        /// <summary>
        /// USB控制器设备ID
        /// </summary>
        public string Antecedent;

        /// <summary>
        /// USB即插即用设备ID
        /// </summary>
        public string Dependent;
    }

    /// <summary>
    /// 监视USB插拔
    /// </summary>
    public class UsbWatcher
    {
        /// <summary>
        /// USB插入事件监视
        /// </summary>
        private ManagementEventWatcher insertWatcher = null;

        /// <summary>
        /// USB拔出事件监视
        /// </summary>
        private ManagementEventWatcher removeWatcher = null;

        /// <summary>
        /// 添加USB事件监视器
        /// </summary>
        /// <param name="usbInsertHandler">USB插入事件处理器</param>
        /// <param name="usbRemoveHandler">USB拔出事件处理器</param>
        /// <param name="withinInterval">发送通知允许的滞后时间</param>
        public bool AddUSBEventWatcher(EventArrivedEventHandler usbInsertHandler, EventArrivedEventHandler usbRemoveHandler, TimeSpan withinInterval)
        {
            try
            {
                ManagementScope Scope = new ManagementScope("root\\CIMV2");
                Scope.Options.EnablePrivileges = true;

                // USB插入监视
                if (usbInsertHandler != null)
                {
                    var insertQuery = GetUsbQueryParamter("__InstanceCreationEvent", withinInterval);
                    insertWatcher = new ManagementEventWatcher(Scope, insertQuery);
                    insertWatcher.EventArrived += usbInsertHandler;
                    insertWatcher.Start();
                }

                // USB拔出监视
                if (usbRemoveHandler != null)
                {
                    var removeQuery = GetUsbQueryParamter("__InstanceDeletionEvent", withinInterval);
                    removeWatcher = new ManagementEventWatcher(Scope, removeQuery);
                    removeWatcher.EventArrived += usbRemoveHandler;
                    removeWatcher.Start();
                }

                return true;
            }

            catch (Exception)
            {
                RemoveUSBEventWatcher();
                return false;
            }
        }

        private WqlEventQuery GetUsbQueryParamter(string eventClassName, TimeSpan withinInterval)
        {
            return new WqlEventQuery(eventClassName, withinInterval, "TargetInstance isa 'Win32_USBControllerDevice'");
        }

        /// <summary>
        /// 移去USB事件监视器
        /// </summary>
        public void RemoveUSBEventWatcher()
        {
            if (insertWatcher != null)
            {
                insertWatcher.Stop();
                insertWatcher.Dispose();
                insertWatcher = null;
            }

            if (removeWatcher != null)
            {
                removeWatcher.Stop();
                removeWatcher.Dispose();
                removeWatcher = null;
            }
        }

        /// <summary>
        /// 定位发生插拔的USB设备
        /// </summary>
        /// <param name="e">USB插拔事件参数</param>
        /// <returns>发生插拔现象的USB控制设备ID</returns>
        public static USBControllerDevice[] WhoUSBControllerDevice(EventArrivedEventArgs e)
        {
            ManagementBaseObject mbo = e.NewEvent["TargetInstance"] as ManagementBaseObject;
            if (mbo != null && mbo.ClassPath.ClassName == "Win32_USBControllerDevice")
            {
                string Antecedent = (mbo["Antecedent"] as string).Replace("\"", string.Empty).Split(new Char[] { '=' })[1];
                string Dependent = (mbo["Dependent"] as string).Replace("\"", string.Empty).Split(new Char[] { '=' })[1];
                return new USBControllerDevice[] { new USBControllerDevice { Antecedent = Antecedent, Dependent = Dependent } };
            }

            return null;
        }
    }


通过以上代码,我们就可以通过注册事件的方式来获取USB设备的插入或者拔出。通过调用WhoUSBControllerDevice方法来获取具体设备的ID。
这里需要注意,因为其实现原理,我们监听的事件可能会触发多次的情况,为了避免这种情况的出现,我们需要将其Watcher先暂停一下,待我们处理结束后在重新启动就可以达到只触发一次的目的了。


var watcher = sender as ManagementEventWatcher;
watcher.Stop();
// 业务代码,逻辑耗时尽量不要太长,以免影响事件的监听
watcher.Start();

以上就是实现监听USB插拔的简易方法。


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/C-%E9%80%9A%E8%BF%87WIM%E7%9B%91%E6%8E%A7USB%E6%8F%92%E6%8B%94.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系