You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:15:55