如何将WinRT的DeviceInformation对象与WMI的Win32_PnPEntity关联?
我使用Windows.Devices.Enumeration命名空间监听设备接入,在事件回调中通过DeviceInformation类获取设备信息。其中System.Devices.DeviceInstanceId属性(即DeviceInformation.Id)描述为“设备的标识,与DeviceInformation.Id的值一致”,我原本期望它是设备实例ID(Device Instance Id),但实际获取的值和Windows系统中其他渠道(比如WMI的Win32_PnPEntity类)拿到的设备实例ID格式、内容都不匹配。
我现在要处理的是通过Thunderbolt连接的SCSI可移动磁盘驱动器,用WMI捕获对应PNP实体时,Win32_PnPEntity的设备ID和WinRT API获取的System.Devices.DeviceInstanceId完全不相似。
我的应用需要将WinRT API获取的设备和WMI中的对应设备关联起来。我知道可以用WMI回调处理设备接入,但这不符合当前代码的使用场景。我想找直接把DeviceInformation对象转换为对应WMI对象的方法,最好不用遍历所有WMI对象,必要的话遍历方案也能接受。
1. 通过设备容器ID关联
DeviceInformation中有一个System.Devices.ContainerId属性,这个值和WMI中Win32_PnPEntity的ContainerID属性完全一致,是最可靠的关联方式:
- 获取
DeviceInformation时指定检索System.Devices.ContainerId:var propertiesToRetrieve = new List<string> { "System.Devices.DeviceInstanceId", "System.Devices.ContainerId" }; var deviceInfo = await DeviceInformation.CreateFromIdAsync(deviceId, propertiesToRetrieve); var containerId = deviceInfo.Properties["System.Devices.ContainerId"].ToString(); - 用容器ID查询对应WMI对象:
using (var searcher = new ManagementObjectSearcher($"SELECT * FROM Win32_PnPEntity WHERE ContainerID = '{containerId}'")) { foreach (var obj in searcher.Get()) { // 此处即为匹配到的WMI设备对象 } }
2. 解析DeviceInformation.Id提取硬件ID匹配
DeviceInformation.Id的格式通常为\\?\usb#vid_xxxx&pid_xxxx#...#{guid},可以从中提取硬件ID前缀(如usb#vid_xxxx&pid_xxxx),再匹配Win32_PnPEntity的HardwareID数组:
- 解析并查询:
var deviceId = deviceInfo.Id; var parts = deviceId.Split(new[] {'#'}, StringSplitOptions.RemoveEmptyEntries); if (parts.Length >= 2) { var hardwareIdPart = $"{parts[0]}#{parts[1]}"; using (var searcher = new ManagementObjectSearcher($"SELECT * FROM Win32_PnPEntity WHERE HardwareID LIKE '%{hardwareIdPart}%'")) { foreach (var obj in searcher.Get()) { // 匹配到的WMI设备对象 } } }
3. 设备实例ID格式转换匹配(兼容性有限)
部分设备的System.Devices.DeviceInstanceId可通过去掉前缀(如\\?\)转换为WMIWin32_PnPEntity的DeviceID格式,可尝试直接对比,但该方法仅适用于部分设备类型。
内容的提问来源于stack exchange,提问作者Scott

