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

使用C#获取设备ID未知的USB打印机VID/PID相关问题咨询

C# 获取USB打印机VID/PID的实现方案

以下为两种常用的Windows平台下的实现方式,均可直接运行获取参数:


方案1:WMI实现(代码简单,无需引入原生API)

该方案依赖系统WMI接口枚举即插即用设备,开发成本更低。

注意:使用前需要先在项目中添加System.Management程序集引用

using System;
using System.Management;
using System.Text.RegularExpressions;

class UsbPrinterInfoGetter
{
    static void Main()
    {
        // 筛选USB接口的物理打印机设备
        var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity WHERE PNPClass = 'Printer' AND Service = 'usbprint'");
        foreach (var device in searcher.Get())
        {
            string[] hardwareIds = (string[])device["HardwareID"];
            if (hardwareIds == null || hardwareIds.Length == 0) continue;
            
            foreach (string id in hardwareIds)
            {
                if (id.StartsWith("USB\\", StringComparison.OrdinalIgnoreCase))
                {
                    // 用正则匹配VID和PID,避免字符串截取出错
                    var vidMatch = Regex.Match(id, @"VID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
                    var pidMatch = Regex.Match(id, @"PID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
                    
                    if (vidMatch.Success && pidMatch.Success)
                    {
                        string printerName = device["Name"]?.ToString() ?? "未知打印机";
                        string vid = vidMatch.Groups[1].Value;
                        string pid = pidMatch.Groups[1].Value;
                        Console.WriteLine($"打印机名称:{printerName},VID:{vid},PID:{pid}");
                    }
                }
            }
        }
    }
}

方案2:SetupAPI原生API实现(推荐,兼容性更高)

该方案直接调用Windows设备管理原生API,枚举结果更完整,不会出现WMI偶尔漏枚举设备的问题。

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

public class SetupApiPrinterGetter
{
    // 打印机设备类固定GUID
    private static Guid GUID_DEVCLASS_PRINTER = new Guid(0x4d36e979, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
    private const int DIGCF_PRESENT = 0x00000002;
    private const int DIGCF_DEVICEINTERFACE = 0x00000010;
    private const int SPDRP_HARDWAREID = 0x00000001;
    private const int ERROR_INSUFFICIENT_BUFFER = 122;

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, string Enumerator, IntPtr hwndParent, uint Flags);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr pDeviceInfoData, ref Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA pDeviceInterfaceData);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA pDeviceInterfaceData, IntPtr pDeviceInterfaceDetailData, uint DeviceInterfaceDetailDataSize, out uint RequiredSize, IntPtr pDeviceInfoData);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr hDevInfo, 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 hDevInfo);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct SP_DEVICE_INTERFACE_DATA
    {
        public int cbSize;
        public Guid InterfaceClassGuid;
        public int Flags;
        public IntPtr Reserved;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct SP_DEVINFO_DATA
    {
        public int cbSize;
        public Guid ClassGuid;
        public int DevInst;
        public IntPtr Reserved;
    }

    public static void GetUsbPrinterVidPid()
    {
        IntPtr hDevInfo = SetupDiGetClassDevs(ref GUID_DEVCLASS_PRINTER, "USB", IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (hDevInfo == IntPtr.Zero) return;

        SP_DEVICE_INTERFACE_DATA interfaceData = new SP_DEVICE_INTERFACE_DATA();
        interfaceData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

        for (uint i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref GUID_DEVCLASS_PRINTER, i, ref interfaceData); i++)
        {
            uint requiredSize = 0;
            SetupDiGetDeviceInterfaceDetail(hDevInfo, ref interfaceData, IntPtr.Zero, 0, out requiredSize, IntPtr.Zero);
            if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) continue;

            IntPtr detailDataBuf = Marshal.AllocHGlobal((int)requiredSize);
            SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
            devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

            try
            {
                Marshal.WriteInt32(detailDataBuf, IntPtr.Size == 4 ? 4 + Marshal.SystemDefaultCharSize : 8);
                if (SetupDiGetDeviceInterfaceDetail(hDevInfo, ref interfaceData, detailDataBuf, requiredSize, out _, ref devInfoData))
                {
                    StringBuilder hardwareIdBuf = new StringBuilder(1024);
                    if (SetupDiGetDeviceRegistryProperty(hDevInfo, ref devInfoData, SPDRP_HARDWAREID, out _, hardwareIdBuf, (uint)hardwareIdBuf.Capacity, out _))
                    {
                        string hardwareId = hardwareIdBuf.ToString();
                        var vidMatch = Regex.Match(hardwareId, @"VID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
                        var pidMatch = Regex.Match(hardwareId, @"PID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
                        if (vidMatch.Success && pidMatch.Success)
                        {
                            string devicePath = Marshal.PtrToStringAuto(detailDataBuf + (IntPtr.Size == 4 ? 4 : 8));
                            Console.WriteLine($"设备路径:{devicePath}\nVID:{vidMatch.Groups[1].Value}\nPID:{pidMatch.Groups[1].Value}\n");
                        }
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(detailDataBuf);
            }
        }
        SetupDiDestroyDeviceInfoList(hDevInfo);
    }
}

注意事项

  • 两种方案都需要程序以管理员权限运行,否则可能出现设备枚举不全、属性读取失败的问题
  • 仅物理USB连接的打印机会返回包含VID/PID的硬件ID,虚拟打印机、网络打印机无该参数
  • 可根据返回的打印机名称字段匹配你当前连接的目标设备,对应读取VID和PID即可

内容的提问来源于stack exchange,提问作者TechnologyEnthusiast

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:36:02