PrintQueue.Refresh无法显示打印机状态,求助Windows Service获取状态方案
我明白你现在的痛点——靠手动移除纸张、打测试页来检测打印机状态完全不现实,尤其是还要覆盖那些没装在服务运行机器上的打印机。咱们一步步来拆解解决这个问题:
核心问题先理清楚
首先得明确两个关键限制:
- 本地已安装打印机:拿不到状态大概率是服务权限不够,或者用的API没抓住精准的错误状态字段;
- 未安装在本机的网络打印机:这类设备的状态信息根本不会存在于本地系统里,必须走网络协议去直接查询打印机本身。
针对性解决方案
1. 修复本地打印机的状态获取
先搞定权限问题
别让服务用Local System账户跑,换成有打印机管理权限的本地管理员或域账户——Local System对部分打印机资源的访问是受限的,这很多时候是隐形的坑。
换个精准的API查询
别只盯着笼统的打印机状态,用WMI的Win32_Printer类,重点看DetectedErrorState字段(这才是反映缺纸、无墨粉这类硬件错误的关键),而不是PrinterStatus(只是整体运行状态)。给你个C#示例(假设你用C#写服务):
using System.Management; public void FetchLocalPrinterStatus() { var printerSearcher = new ManagementObjectSearcher("SELECT Name, PrinterStatus, DetectedErrorState FROM Win32_Printer"); foreach (var printerObj in printerSearcher.Get()) { string printerName = printerObj["Name"].ToString(); uint errorState = (uint)printerObj["DetectedErrorState"]; string errorDesc = errorState switch { 0 => "无错误", 3 => "缺纸", 4 => "无墨粉/碳粉不足", 5 => "卡纸", 9 => "打印机离线", 10 => "打印机过热", _ => "未知错误" }; Console.WriteLine($"[{printerName}] 当前状态: {errorDesc}"); } }
如果WMI查询还是有问题,试试直接调用Windows打印池API(OpenPrinter+GetPrinter),这个是系统级别的,权限够的话更可靠。
2. 搞定非本地安装的网络打印机
这类打印机只能通过网络协议直接查询,最通用的方案是SNMP:
第一步:确认打印机开启SNMP
大部分品牌的网络打印机默认开启SNMP(社区版可能需要手动在打印机Web管理界面打开),社区字符串默认是public。
第二步:用SNMP查询状态
借助SNMP库(比如SnmpSharpNet),查询打印机MIB库中的指定OID来获取错误状态:
- 缺纸OID:
.1.3.6.1.2.1.43.10.2.1.4.1.1 - 无墨粉OID:
.1.3.6.1.2.1.43.11.1.1.9.1.1 - 卡纸OID:
.1.3.6.1.2.1.43.10.2.1.5.1.1
示例代码:
using SnmpSharpNet; public string GetNetworkPrinterStatus(string printerIp, string community = "public") { var snmpClient = new SimpleSnmp(printerIp, community); if (!snmpClient.Valid) return "SNMP连接失败,请检查打印机设置"; // 查询缺纸状态 var paperOid = new Oid(".1.3.6.1.2.1.43.10.2.1.4.1.1"); var result = snmpClient.Get(SnmpVersion.Ver2, new Oid[] { paperOid }); if (result != null && result.ContainsKey(paperOid)) { var paperStatus = (Integer32)result[paperOid]; return paperStatus.Value == 1 ? "纸张充足" : "缺纸"; } return "无法获取打印机状态"; }
如果打印机支持REST API或者有标准的Web管理接口,也可以用HTTP请求抓取状态页面,但SNMP是跨品牌最通用的方案。
3. 服务运行的关键配置
- 权限兜底:服务账户必须同时具备本地打印机管理权限和网络访问权限(访问打印机IP的权限),域账户是最优选择;
- 实时监控替代轮询:别定时去查状态,用WMI事件监听打印机状态变化,效率更高:
var statusWatcher = new ManagementEventWatcher( new WqlEventQuery("SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Printer'")); statusWatcher.EventArrived += (sender, e) => { var changedPrinter = (ManagementObject)e.NewEvent["TargetInstance"]; // 在这里处理状态变化逻辑 }; statusWatcher.Start();
避坑提醒
- 防火墙要开:服务运行机器和打印机的防火墙都要允许UDP 161端口(SNMP默认端口);
- 本地打印机驱动要完整:如果驱动安装不完整,WMI根本读不到正确的状态,建议重装官方驱动;
- 别碰“允许服务与桌面交互”:这个选项不安全,权限问题还是靠配置正确的服务账户解决。
内容的提问来源于stack exchange,提问作者Bestter
相关产品推荐
相关产品推荐

