使用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
相关产品推荐
相关产品推荐

