You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

打印机状态变更通知无法接收问题求助(附测试代码)

问题:监控打印机状态变更无通知,但作业状态监控正常

我想开发一款能在打印机打印时显示提示信息的应用。我写了一个控制台测试程序,但接收不到打印机状态变更的通知。需要说明的是,当我用JOB_NOTIFY_TYPE和JOB_NOTIFY_FIELD_STATUS监控作业状态时,能正常收到通知。

请问打印机是否不会发送状态变更通知?这是否和打印机类型或驱动有关?

测试代码

program PrinterMonitor;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,
  Winapi.WinSpool;

const
  PrinterField: WORD = PRINTER_NOTIFY_FIELD_STATUS;

var
  PrinterName: string;
  hStopEvent: THandle;
  hPrinter: THandle;
  hPrintNotify: THandle;
  pno: TPrinterNotifyOptions;
  pnot: TPrinterNotifyOptionsType;
  pni: Pointer;
  dwChange: DWORD;
  WaitHandles: array[0..1] of THandle;

function CtrlHandler(fdwCtrlType: DWORD): BOOL; stdcall;
begin
  Result := False;
  case fdwCtrlType of
    CTRL_C_EVENT, CTRL_CLOSE_EVENT:
    begin
      SetEvent(hStopEvent);
      Result := True;
    end;
  end;
end;

procedure GetPrinterNotifyData(const Info: TPrinterNotifyInfo);
var
  I: Integer;
begin
  for I := 0 to Info.Count - 1 do
  begin
    with Info.aData[I] do
    begin
      case wType of
        PRINTER_NOTIFY_TYPE:
        begin
          case Field of
            PRINTER_NOTIFY_FIELD_STATUS: WriteLn('Printer status: ', NotifyData.adwData[0]);
          end;
        end;
      end;
    end;
  end;
end;

begin
  if ParamCount < 1 then
  begin
    WriteLn('No printer name specified.');
    Exit;
  end;
  PrinterName := ParamStr(1); //pass a printer name as argument

  OpenPrinter(PWideChar(PrinterName), hPrinter, nil);
  if hPrinter = 0 then
  begin
    WriteLn('Cannot open printer "', PrinterName, '". ErrorCode: ', GetLastError);
    Exit;
  end;

  pnot.wType := PRINTER_NOTIFY_TYPE;
  pnot.Count := 1;
  pnot.pFields := @PrinterField;

  pno.Version := 2;
  pno.Count := 1;
  pno.pTypes := @pnot;

  hStopEvent := CreateEvent(nil, True, False, nil);
  if hStopEvent = 0 then
  begin
    WriteLn('Cannot create stop event. ErrorCode: ', GetLastError);
    ClosePrinter(hPrinter);
    Exit;
  end;

  hPrintNotify := FindFirstPrinterChangeNotification(hPrinter, 0, 0, @pno);
  if hPrintNotify = 0 then
  begin
    WriteLn('Cannot start monitoring. ErrorCode: ', GetLastError);
    ClosePrinter(hPrinter);
    CloseHandle(hStopEvent);
    Exit;
  end;

  WaitHandles[0] := hStopEvent;
  WaitHandles[1] := hPrintNotify;

  SetConsoleCtrlHandler(@CtrlHandler, True); // handling CTRL+C & close console events for stop monitoring

  WriteLn('==== Monitor started ====');
  while True do
  begin
    case WaitForMultipleObjects(2, @WaitHandles, False, INFINITE) of
      WAIT_OBJECT_0: // hStopEvent signalled
      begin
        WriteLn('==== Monitor stopped ====');
        Break;
      end;
      WAIT_OBJECT_0+1: // hPrintNotify signalled
      begin
        if not FindNextPrinterChangeNotification(hPrintNotify, dwChange, nil, pni) then
        begin
          WriteLn('Cannot get notify changes data.');
          Break;
        end;
        GetPrinterNotifyData(PPrinterNotifyInfo(pni)^);
        FreePrinterNotifyInfo(PPrinterNotifyInfo(pni));
      end;
      else
      begin
        WriteLn('Wait failed');
        Break;
      end;
    end;
  end;
  FindClosePrinterChangeNotification(hPrintNotify);
  ClosePrinter(hPrinter);
  CloseHandle(hStopEvent);
end.

回答

  1. 打印机状态通知的触发逻辑
    打印机状态变更通知并非针对打印作业的提交或完成,而是对应硬件层面的状态变化,比如打印机离线/在线切换、缺纸、卡纸、墨粉耗尽、设备被暂停或恢复等场景。普通的作业流转(如作业开始打印、完成)属于作业状态范畴,不会触发打印机状态的通知。

  2. 打印机类型与驱动的影响
    这确实和打印机类型及驱动实现直接相关:

    • 物理打印机:主流品牌的现代驱动会完整实现状态上报,但老旧驱动或第三方兼容性差的驱动可能遗漏部分状态通知逻辑。
    • 虚拟打印机(如PDF打印机、虚拟传真机):这类设备没有实体硬件状态,驱动通常不会发送打印机状态变更通知,除非特意模拟相关状态。
    • 网络打印机:依赖打印机的网络管理协议(如SNMP)和驱动的适配,如果打印机本身不支持状态上报,或驱动未实现该功能,也无法收到通知。
  3. 代码优化建议
    你的代码中FindFirstPrinterChangeNotification的第二个参数(fdwFilter)传了0,虽然通过TPrinterNotifyOptions指定了监控字段,但部分驱动需要明确的过滤器标志才能触发通知。建议修改为:

hPrintNotify := FindFirstPrinterChangeNotification(hPrinter, PRINTER_CHANGE_STATUS, 0, @pno);

另外,可以先调用GetPrinter获取打印机当前的PRINTER_INFO_2结构中的Status字段,确认目标打印机是否存在可触发状态变更的场景(比如手动让打印机离线),以此验证通知机制是否正常。

内容的提问来源于stack exchange,提问作者yonni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:27:09