监控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/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。