Win32_DeviceChangeEvent 仅报告发生的事件类型和事件时间(uint64,表示 1601 年 1 月 1 日之后的 100 纳秒间隔,UTC)。如果您还想知道什么是到达或被删除的,那就没有多大用处了。
我建议改用WqlEventQuery 类,将其EventClassName 设置为__InstanceOperationEvent。
该系统类提供了一个 TargetInstance 属性,可以将其转换为 ManagementBaseObject,这是一个完整的管理对象,还提供有关生成事件的设备的基本信息。
在这些信息中(包括设备的友好名称),PNPDeviceID,可用于构建其他查询以进一步检查所引用的设备。
WqlEventQuery 的Condition 属性可以在此处设置为TargetInstance ISA 'Win32_DiskDrive'。
它可以设置为任何其他感兴趣的Win32_ 类。
设置事件监听器(本地机器):
(事件处理程序称为 DeviceChangedEvent)
var query = new WqlEventQuery() {
EventClassName = "__InstanceOperationEvent",
WithinInterval = new TimeSpan(0, 0, 3),
Condition = @"TargetInstance ISA 'Win32_DiskDrive'"
};
var scope = new ManagementScope("root\\CIMV2");
using (var moWatcher = new ManagementEventWatcher(scope, query))
{
moWatcher.Options.Timeout = ManagementOptions.InfiniteTimeout;
moWatcher.EventArrived += new EventArrivedEventHandler(DeviceChangedEvent);
moWatcher.Start();
}
事件处理程序在e.NewEvent.Properties["TargetInstance"] 中接收代表Win32_DiskDrive 类的管理对象。
请参阅有关此处直接可用的属性的文档。
e.NewEvent.ClassPath.ClassName 报告的感兴趣的__InstanceOperationEvent 派生类可以是:
__InstanceCreationEvent:检测到新设备到达。
__InstanceDeletionEvent:检测到设备移除。
__InstanceModificationEvent:现有设备已被某种方式修改。
请注意,该事件是在辅助线程中引发的,我们需要BeginInvoke() UI 线程以使用新信息更新 UI。
▶ 这里应该避免Invoke(),因为它是同步的:它会阻塞处理程序直到方法完成。此外,在这种情况下,死锁并不是完全可能的。
请参阅此处:Get serial number of USB storage device,该类提供了有关设备的大部分可用信息(信息被过滤以仅显示 USB 设备,但可以删除过滤器)。
private void DeviceChangedEvent(object sender, EventArrivedEventArgs e)
{
using (var moBase = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value)
{
string oInterfaceType = moBase?.Properties["InterfaceType"]?.Value.ToString();
string devicePNPId = moBase?.Properties["PNPDeviceID"]?.Value.ToString();
string deviceDescription = moBase?.Properties["Caption"]?.Value.ToString();
string eventMessage = $"{oInterfaceType}: {deviceDescription} ";
switch (e.NewEvent.ClassPath.ClassName)
{
case "__InstanceDeletionEvent":
eventMessage += " removed";
BeginInvoke(new Action(() => UpdateUI(eventMessage)));
break;
case "__InstanceCreationEvent":
eventMessage += "inserted";
BeginInvoke(new Action(() => UpdateUI(eventMessage)));
break;
case "__InstanceModificationEvent":
default:
Console.WriteLine(e.NewEvent.ClassPath.ClassName);
break;
}
}
}
private void UpdateUI(string message)
{
//Update the UI controls with information provided by the event
}