printersettings.installedprinters仅返回注册表中已安装的打印机名称列表,不反映实际在线状态;需结合wmi(win32_printer)或printqueue判断实时状态,跨平台需绕开system.printing改用cups等方案。

用 PrinterSettings.InstalledPrinters 获取已安装打印机列表最直接
Windows 系统里,只要打印机驱动装好了、在“设备和打印机”里可见,PrinterSettings.InstalledPrinters 就能列出来——它不区分是否在线、是否共享、是否默认,只管注册表里有没有这台打印机的配置项。
常见错误是以为它会返回当前可通信的打印机,结果代码跑起来发现列表里有台“HP LaserJet XXX(脱机)”,程序却照常把它当可用设备用了。这不是 bug,是设计如此。
-
PrinterSettings.InstalledPrinters返回的是StringCollection,不是数组,遍历时别直接用[i]下标访问,用foreach或转成ToArray() - 它不触发权限弹窗,也不需要管理员权限,适合 UI 初始化时快速填充下拉框
- 如果某台打印机刚装完驱动但没重启应用,可能要等几秒再调用,.NET 不自动监听注册表变更
判断打印机是否实际在线得靠 PrintQueue + WMI 查询
想确认“这台打印机现在插着 USB、开了电源、没卡纸”,光看名字不够。得用 System.Printing 命名空间里的 PrintServer 和 PrintQueue,或者更轻量的 WMI 查询 Win32_Printer。
用 PrintQueue 的问题是:它默认只对本地打印服务器有效;如果目标打印机是网络共享的(比如 \serverHP-OfficeJet),得先构造对应路径的 PrintServer 实例,否则抛 PrintSystemException。
- WMI 方式更通用:
SELECT Name, Status, PrinterStatus FROM Win32_Printer,其中PrinterStatus = 3表示就绪,Status = "Error"或PrinterStatus = 8多半是离线或缺纸 -
PrintQueue构造时传错服务器名会静默失败(返回 null),不是抛异常,容易漏判 - WMI 查询需引用
System.Management,且 Windows 10/11 默认禁用 WMI 服务组策略时会超时,建议加 2 秒超时控制
别用 ManagementObjectSearcher 查所有设备来凑打印机
有人搜“C# 列出设备列表”,顺手抄了查 Win32_PnPEntity 的代码,结果一堆鼠标、键盘、蓝牙设备混在结果里,再用 Where-Object { $_.Name -like "*print*" } 模糊过滤——这不可靠。
Win32_PnPEntity 里打印机设备没有统一标识字段,有些叫“HP LaserJet”,有些叫“Microsoft Print to PDF”,还有些只显示“USB Printing Support”,根本没法稳定识别。
- 真正属于打印子系统的设备,WMI 类是
Win32_Printer,不是Win32_PnPEntity -
Win32_Printer的Local属性能区分本地/网络打印机,Shared属性告诉你是否被共享,这些字段Win32_PnPEntity根本没有 - 用错类会导致:PDF 虚拟打印机漏掉、网络打印机识别为“未知设备”、甚至把扫描仪当打印机返回
兼容性注意:.NET Core/.NET 5+ 里 System.Printing 只支持 Windows
如果你项目目标是跨平台(比如将来要跑 Linux/macOS),System.Printing 直接不可用——它在非 Windows 平台上连编译都过不去,不是运行时报错。
而 PrinterSettings.InstalledPrinters 在 .NET 5+ 中仍可用,但它底层还是调 Windows API,Linux/macOS 上返回空集合。别指望它“优雅降级”。
- 跨平台方案只能绕开系统 API,改用 CUPS 命令行(Linux)或
lpstat -p,再用Process.Start调用并解析输出 - 如果只做 Windows 工具,推荐组合使用:
InstalledPrinters快速列名 + WMI 补充状态,别硬上PrintQueue增加部署复杂度 - .NET 6+ 的
Microsoft.Extensions.DependencyInjection无法注入PrintServer,它不是无状态服务,别在 DI 容器里注册单例
事情说清了就结束。打印机名看似简单,但“已连接”这个词在不同上下文里指代的东西差得挺远——驱动注册、网络可达、物理通电、队列空闲,每个环节都可能断在半路。











