如何在C#及.NET 6中获取设备的PID和VID?
在C# .NET 6中获取USB设备的VID和PID
问题原因说明
Win32_USBDevice类依赖特定WMI Provider,部分Windows系统(如精简版)未预装,因此会出现找不到类的异常。Win32_DiskDrive仅枚举磁盘类设备,非存储类USB设备(如鼠标、键盘)不会被识别,且空引用异常通常是因为未判断查询结果或属性值是否为null导致。
方法一:使用WMI查询(兼容性好)
通过Win32_PnPEntity类枚举所有USB即插即用设备,从设备ID中提取VID和PID,代码已做空值判断避免异常:
using System; using System.Management; namespace UsbDeviceQuery { class Program { static void Main(string[] args) { // 筛选带USB标识的即插即用设备 var query = new SelectQuery("Win32_PnPEntity", "PNPDeviceID LIKE '%USB%'"); using var searcher = new ManagementObjectSearcher(query); foreach (var device in searcher.Get()) { // 避免属性为空导致的空引用 var pnpId = device["PNPDeviceID"]?.ToString(); var deviceName = device["Name"]?.ToString() ?? "未知设备"; if (string.IsNullOrEmpty(pnpId)) continue; // 从PNPDeviceID中提取VID和PID(格式:VID_XXXX&PID_YYYY) int vidPos = pnpId.IndexOf("VID_", StringComparison.OrdinalIgnoreCase); int pidPos = pnpId.IndexOf("PID_", StringComparison.OrdinalIgnoreCase); if (vidPos == -1 || pidPos == -1) continue; string vid = pnpId.Substring(vidPos + 4, 4); string pid = pnpId.Substring(pidPos + 4, 4); Console.WriteLine($"设备名称: {deviceName}"); Console.WriteLine($"VID: 0x{vid}"); Console.WriteLine($"PID: 0x{pid}\n"); } } } }
方法二:使用Windows原生API(稳定性高)
直接调用SetupDi系列底层API,不依赖WMI,适合对兼容性要求高的场景:
using System; using System.Runtime.InteropServices; using System.Text; namespace UsbDeviceApi { class Program { [DllImport("setupapi.dll", SetLastError = true)] private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr hwndParent, uint Flags); [DllImport("setupapi.dll", SetLastError = true)] private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, uint MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData); [DllImport("setupapi.dll", SetLastError = true)] private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, uint Property, out uint PropertyRegDataType, StringBuilder PropertyBuffer, uint PropertyBufferSize, out uint RequiredSize); [DllImport("setupapi.dll", SetLastError = true)] private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); [StructLayout(LayoutKind.Sequential)] private struct SP_DEVINFO_DATA { public uint cbSize; public Guid ClassGuid; public uint DevInst; public IntPtr Reserved; } private static readonly Guid GUID_DEVINTERFACE_USB_DEVICE = new("{A5DCBF10-6530-11D2-901F-00C04FB951ED}"); private const uint DIGCF_DEVICEINTERFACE = 0x10; private const uint DIGCF_PRESENT = 0x02; private const uint SPDRP_HARDWAREID = 0x00000001; private const uint SPDRP_FRIENDLYNAME = 0x0000000C; static void Main(string[] args) { IntPtr deviceInfoSet = IntPtr.Zero; try { // 获取当前连接的所有USB设备 deviceInfoSet = SetupDiGetClassDevs(ref GUID_DEVINTERFACE_USB_DEVICE, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoSet == IntPtr.Zero) { Console.WriteLine("无法获取USB设备列表"); return; } SP_DEVINFO_DATA deviceInfoData = new() { cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA)) }; uint index = 0; while (SetupDiEnumDeviceInfo(deviceInfoSet, index, ref deviceInfoData)) { StringBuilder hardwareIdBuffer = new(1024); uint regType; uint reqSize; // 获取硬件ID(包含VID/PID) if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, SPDRP_HARDWAREID, out regType, hardwareIdBuffer, (uint)hardwareIdBuffer.Capacity, out reqSize)) { string hardwareId = hardwareIdBuffer.ToString(); if (!hardwareId.Contains("VID_") || !hardwareId.Contains("PID_")) continue; int vidPos = hardwareId.IndexOf("VID_", StringComparison.OrdinalIgnoreCase); int pidPos = hardwareId.IndexOf("PID_", StringComparison.OrdinalIgnoreCase); string vid = hardwareId.Substring(vidPos + 4, 4); string pid = hardwareId.Substring(pidPos + 4, 4); // 获取设备友好名称 StringBuilder nameBuffer = new(1024); SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, SPDRP_FRIENDLYNAME, out regType, nameBuffer, (uint)nameBuffer.Capacity, out reqSize); string deviceName = nameBuffer.Length > 0 ? nameBuffer.ToString() : "未知设备"; Console.WriteLine($"设备名称: {deviceName}"); Console.WriteLine($"VID: 0x{vid}"); Console.WriteLine($"PID: 0x{pid}\n"); } index++; deviceInfoData.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); } } finally { // 释放资源避免内存泄漏 if (deviceInfoSet != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(deviceInfoSet); } } } } }
内容的提问来源于stack exchange,提问作者Xwilarg
相关产品推荐
相关产品推荐

