C#如何读取Windows10 USB设备属性中的最后已知父设备信息
通过C#读取Windows 10 USB设备最后已知父设备的方案
Win32_PnPEntity WMI类未直接暴露「最后已知父设备」字段,你需要调用Windows原生的SetupAPI(设备安装API)读取DEVPKEY_Device_Parent属性,这是设备管理器展示该字段的底层调用接口。
必要的P/Invoke声明
using System; using System.Runtime.InteropServices; using System.Text; public static class SetupApi { public const int DIGCF_PRESENT = 0x00000002; public const int DIGCF_ALLCLASSES = 0x00000004; public const int DEVPROP_TYPE_STRING = 0x00000012; [StructLayout(LayoutKind.Sequential)] public struct SP_DEVINFO_DATA { public int cbSize; public Guid ClassGuid; public int DevInst; public IntPtr Reserved; } [StructLayout(LayoutKind.Sequential)] public struct DEVPROPKEY { public Guid fmtid; public int pid; } public static readonly DEVPROPKEY DEVPKEY_Device_Parent = new DEVPROPKEY { fmtid = new Guid("4340A6C5-93FA-4706-972C-7B648008A5A7"), pid = 8 }; [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, string Enumerator, IntPtr hwndParent, int Flags); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, int MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetupDiGetDeviceProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref DEVPROPKEY PropertyKey, out int PropertyType, StringBuilder PropertyBuffer, int PropertyBufferSize, out int RequiredSize, int Flags); [DllImport("setupapi.dll", SetLastError = true)] public static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); }
核心读取逻辑
public static List<string> GetAllUsbDeviceParentIds() { var parentIds = new List<string>(); Guid emptyGuid = Guid.Empty; IntPtr deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref emptyGuid, "USB", IntPtr.Zero, SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_ALLCLASSES); if (deviceInfoSet == IntPtr.Zero) return parentIds; try { SetupApi.SP_DEVINFO_DATA devInfoData = new SetupApi.SP_DEVINFO_DATA(); devInfoData.cbSize = Marshal.SizeOf(devInfoData); for (int i = 0; SetupApi.SetupDiEnumDeviceInfo(deviceInfoSet, i, ref devInfoData); i++) { int propType; int requiredSize; // 第一次调用获取所需缓冲区大小 SetupApi.SetupDiGetDeviceProperty(deviceInfoSet, ref devInfoData, ref SetupApi.DEVPKEY_Device_Parent, out propType, null, 0, out requiredSize, 0); if (propType != SetupApi.DEVPROP_TYPE_STRING) continue; StringBuilder sb = new StringBuilder(requiredSize); if (SetupApi.SetupDiGetDeviceProperty(deviceInfoSet, ref devInfoData, ref SetupApi.DEVPKEY_Device_Parent, out propType, sb, sb.Capacity, out requiredSize, 0)) { parentIds.Add(sb.ToString()); } } } finally { SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } return parentIds; }
注意事项
- 程序需要管理员权限运行,否则部分受限设备的属性无法正常读取
- 接口返回的值为父设备的实例ID,你可以通过同样的SetupAPI接口查询该ID对应的设备名称、制造商等其他属性
- 该方案仅兼容Windows 10及以上版本操作系统
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

