PrintQueue.GetPrintJobInfoCollection() 是获取真实打印状态的唯一可靠方式,需以管理员权限通过 PrintServer 初始化队列,JobStatus 为位标志须用 & 判断,刷新间隔不低于2秒并缓存关键字段比对状态变化。
用 PrintQueue.GetPrintJobInfoCollection() 查当前打印任务
windows 打印子系统里,真正能拿到“正在打印中”“已暂停”“出错”这些状态的,是 printqueue 对象下的作业集合,不是靠轮询 printdocument 的事件。很多人误以为 printdocument.printed 或 printcompleted 能反映队列真实状态,其实它们只在本地触发,且不包含失败重试、卡纸、缺纸等系统级反馈。
实操要点:
-
PrintQueue需要以管理员权限或打印机管理权限打开,否则GetPrintJobInfoCollection()会抛Access is denied - 必须用
PrintServer初始化队列,不能只靠new PrintQueue(...)—— 否则返回空集合或ObjectDisposedException - 每个
PrintSystemJobInfo的JobStatus是位标志(bit flags),比如JobStatus.Paused | JobStatus.Error,得用&判断,不能直接== - 刷新频率建议 ≥ 2 秒,太密会触发 Windows 打印后台处理程序(spooler)限流,返回空或旧快照
var server = new PrintServer();
var queue = server.GetPrintQueue("HP LaserJet MFP M428fdw");
var jobs = queue.GetPrintJobInfoCollection();
foreach (var job in jobs)
{
if ((job.JobStatus & PrintJobStatus.Error) != 0)
Console.WriteLine($"ID {job.JobIdentifier} 出错:{job.JobStatus}");
}
监听 PrintSystemObject.Refresh() 不等于实时推送
没有真正的“事件驱动”接口。所谓监听,本质是定时调用 Refresh() + 比对上次快照。Windows 不提供类似 WMI Win32_PrintJob 的事件订阅机制(那个也延迟高、权限更苛刻)。
常见错误现象:
- 用
Timer每 500ms 刷新一次,结果 spooler 报RPC_S_SERVER_UNAVAILABLE—— 这是 Windows 主动拒绝高频查询 - 只比对
JobIdentifier,漏掉同 ID 任务状态升级(比如从Printing变成Error) - 没处理
PrintSystemJobInfo的生命周期:任务完成几秒后对象可能被回收,再访问JobStatus抛ObjectDisposedException
稳妥做法是每次刷新后深拷贝关键字段(JobIdentifier、JobStatus、NumberOfPagesPrinted),用字典缓存上一轮状态,再逐项比对。
PrintJobStatus 里哪些值代表“真失败”,哪些只是中间态
不是所有带 Error 的状态都需要告警。Windows 把“缺纸”“卡纸”“脱机”全塞进同一个枚举,但业务含义差很远。
关键区分点:
-
PrintJobStatus.Error单独出现 → 大概率是驱动崩溃或文档格式损坏,任务基本不可恢复 -
PrintJobStatus.PaperJam | PrintJobStatus.NoPaper→ 物理问题,人工干预后可恢复,别立刻删任务 -
PrintJobStatus.Deleting或PrintJobStatus.Printing后突然消失 → 任务已被用户取消或 spooler 清理,不是异常 -
PrintJobStatus.UserIntervention→ 很多厂商自定义弹窗(如双面手动翻页提示),需查打印机型号文档确认行为
注意:PrintJobStatus 在 .NET Framework 和 .NET 5+ 中字段名一致,但部分值(如 PrintJobStatus.WarmingUp)在旧驱动下永远不出现,别写死判断逻辑。
为什么不用 WMI 或 PowerShell 替代?
有人试过 Get-WmiObject -Class Win32_PrintJob 或 System.Management 查询,结果更糟:WMI 返回的 JobStatus 字符串字段(如 "Error")和 PrintSystemJobInfo.JobStatus 的位标志不对应,且 WMI 查询本身延迟常达 5–10 秒,还容易因权限策略被禁用。
真实限制:
- PowerShell 的
Get-PrintJob(Windows 10 1809+)底层仍走同一套 spooler API,但封装层加了额外锁,高并发时响应更慢 - 所有方案都绕不开
Spooler服务状态:如果它被手动停止,PrintServer构造就会失败,且不会自动重连 - 远程打印机(如 IP 打印机)必须先在本地添加为“TCP/IP 端口打印机”,否则
PrintServer根本识别不到队列名
最易被忽略的一点:PrintQueue 实例不是线程安全的,多个线程同时调用 GetPrintJobInfoCollection() 会导致随机 COMException,必须加锁或单线程轮询。











