I would like to develop an application that displays a message when the printer prints.
I created a small test application for the console, but for some reason I don't get any notification of a change in the printer state. It should be noted that when I checked the job status in this way (with JOB_NOTIFY_TYPE
and JOB_NOTIFY_FIELD_STATUS
), notifications about the job status were indeed received.
Does the printer not send notifications? (And is it related to the printer type and/or driver?)
Here is the code to test:
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.
When I run your code and then pause and resume the print queue, it works fine:
==== Monitor started ====
Printer status: 131073
Printer status: 131072
The value 131073 = 0x20001, which is comprised of the enums:
PRINTER_STATUS_TONER_LOW | PRINTER_STATUS_PAUSED