如何获取Windows设备中WMI未返回的打印机型号、序列号等信息?
解决Windows物理打印机型号、序列号获取问题
方案1:通过WMI关联查询硬件设备信息
Win32_Printer偏向打印队列配置,打印机的硬件信息(型号、序列号)通常存储在PnP设备类中。可以通过Win32_PrinterDevice关联类,将打印队列与对应硬件设备绑定,再从Win32_PnPEntity中提取硬件详情。
示例代码
public async Task<List<Printer>> DiscoverPrintersWithHardwareInfo() { List<Printer> printers = new(); try { string query = @" SELECT p.Name, p.DriverName, pnp.DeviceID, pnp.Description, pnp.SerialNumber, pnp.Model FROM Win32_Printer p JOIN Win32_PrinterDevice pd ON p.Name = pd.PrinterName JOIN Win32_PnPEntity pnp ON pd.DeviceID = pnp.DeviceID WHERE p.Local = TRUE OR p.Network = TRUE"; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); foreach (ManagementObject item in searcher.Get()) { var printer = new Printer { Name = item["Name"]?.ToString(), DriverName = item["DriverName"]?.ToString(), Model = item["Model"]?.ToString(), SerialNumber = item["SerialNumber"]?.ToString(), DeviceId = item["DeviceID"]?.ToString() }; printers.Add(printer); } } catch (Exception ex) { await _databaseService.LogException(ex); } return printers; }
注意:部分打印机是否暴露序列号,取决于设备驱动是否上报该信息。
方案2:调用Windows打印后台处理程序API
使用GetPrinter2函数可获取底层打印机信息,其中PRINTER_INFO_9结构体包含设备硬件ID,结合SetupAPI能进一步查询硬件详情。
示例代码思路(C# P/Invoke)
[DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool GetPrinter2( IntPtr hPrinter, int Level, IntPtr pPrinterInfo, int cbBuf, out int pcbNeeded); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct PRINTER_INFO_9 { public string pszDeviceName; } public string GetPrinterHardwareId(string printerName) { IntPtr hPrinter = IntPtr.Zero; if (OpenPrinter(printerName, out hPrinter, IntPtr.Zero)) { try { int cbNeeded = 0; GetPrinter2(hPrinter, 9, IntPtr.Zero, 0, out cbNeeded); IntPtr pInfo = Marshal.AllocHGlobal(cbNeeded); if (GetPrinter2(hPrinter, 9, pInfo, cbNeeded, out _)) { PRINTER_INFO_9 info = Marshal.PtrToStructure<PRINTER_INFO_9>(pInfo); return info.pszDeviceName; } Marshal.FreeHGlobal(pInfo); } finally { ClosePrinter(hPrinter); } } return null; }
拿到硬件ID后,可使用SetupDiGetDeviceRegistryProperty函数读取设备的序列号(SPDRP_SERIALNUMBER)和型号(SPDRP_FRIENDLYNAME)。
方案3:读取注册表
打印机硬件信息会存在PnP设备的注册表项中,路径通常为HKLM\SYSTEM\CurrentControlSet\Enum\<硬件ID路径>,包含SerialNumber、FriendlyName等值。可通过WMI获取的设备ID拼接路径后读取对应值。
示例代码
public string GetPrinterSerialFromRegistry(string deviceId) { string registryPath = $"SYSTEM\\CurrentControlSet\\Enum\\{deviceId}"; using (var key = Registry.LocalMachine.OpenSubKey(registryPath)) { return key?.GetValue("SerialNumber")?.ToString(); } }
总结
- 优先尝试方案1,实现简单无需额外P/Invoke;
- 若方案1无法获取所需信息,再用方案2,能获取最全面的硬件信息,但需处理较多Win32 API调用;
- 方案3作为补充,适用于特定设备驱动未正确上报信息的场景。
内容的提问来源于stack exchange,提问作者Coreman
相关产品推荐
相关产品推荐

