Cannot get the correct printer status

Viewed 846

I am using Delphi 10.3 to create a program that prints labels with barcodes. I do not want the printer to queue multiple jobs instead i want to start printing the next job after the previous is finished and receive ready status from the printer. The status of the printer is always ready, even if it is offline!

I use this functions to get the status of the printer:

function TPrintQRForm.GetCurrentPrinterHandle() : THandle;
var
  Device, Driver, Port : Array[0..255] of Char;
  hDeviceMode : THandle;

begin
  Printer.GetPrinter(Device, Driver, Port, hDeviceMode);

  if not Winspool.OpenPrinter(@Device, Result, nil) then
  begin
    RaiseLastOSError();
  end;
end;

function TPrintQRForm.GetCurrentPrinterInformation() : TPrinterInfo;
var
  hPrinter : THandle;
  pInfo : PPrinterInfo2;
  bytesNeeded : DWORD;

begin
  hPrinter := GetCurrentPrinterHandle();
  try
    Winspool.GetPrinter(hPrinter, 2, Nil, 0, @bytesNeeded);
    pInfo := AllocMem(bytesNeeded);

    try
      Winspool.GetPrinter(hPrinter, 2, pInfo, bytesNeeded, @bytesNeeded);
      Result.ServerName := pInfo^.pServerName;
      Result.PrinterName := pInfo^.pPrinterName;
      Result.ShareName := pInfo^.pShareName;
      Result.PortName := pInfo^.pPortName;
      Result.DriverName := pInfo^.pDriverName;
      Result.Comment := pInfo^.pComment;
      Result.Location := pInfo^.pLocation;
      Result.DeviceMode := pInfo^.pDevMode;
      Result.SepFile := pInfo^.pSepFile;
      Result.PrintProcessor := pInfo^.pPrintProcessor;
      Result.DataType := pInfo^.pDatatype;
      Result.Parameters := pInfo^.pParameters;
      Result.SecurityDescriptor := pInfo^.pSecurityDescriptor;
      Result.Attributes := pInfo^.Attributes;
      Result.DefaultPriority := pInfo^.DefaultPriority;
      Result.StartTime := pInfo^.StartTime;
      Result.UntilTime := pInfo^.UntilTime;
      Result.Status := pInfo^.Status;
      Result.Jobs := pInfo^.cJobs;
      Result.AveragePPM := pInfo^.AveragePPM;
    finally
      FreeMem(pInfo);
    end;
  finally
    ClosePrinter(hPrinter);
  end;
end;

And then on a certain event i check for printer status using this code:

  PrinterInfo := GetCurrentPrinterInformation();

  while PrinterInfo.Status <> 0 do
  begin
    if PrinterInfo.Status = PRINTER_STATUS_PRINTING then
    begin
      // Get information about the selected printer
      PrinterInfo := GetCurrentPrinterInformation();
      
      // Process messages from the OS and do not freeze the UI
      Application.ProcessMessages;

      Continue;
    end;

    Case PrinterInfo.Status of
      PRINTER_STATUS_PAUSED             : ShowMessage('The printer is paused.');
      PRINTER_STATUS_ERROR              : ShowMessage('The printer is in an error state.');
      PRINTER_STATUS_PENDING_DELETION   : ShowMessage('The printer is being deleted.');
      PRINTER_STATUS_PAPER_JAM          : ShowMessage('Paper is jammed in the printer.');
      PRINTER_STATUS_PAPER_OUT          : ShowMessage('The printer is out of paper.');
      PRINTER_STATUS_MANUAL_FEED        : ShowMessage('The printer is in a manual feed state.');
      PRINTER_STATUS_PAPER_PROBLEM      : ShowMessage('The printer has a paper problem.');
      PRINTER_STATUS_OFFLINE            : ShowMessage('The printer is offline.');
      PRINTER_STATUS_IO_ACTIVE          : ShowMessage('The printer is in an active input/output state.');
      PRINTER_STATUS_BUSY               : ShowMessage('The printer is busy.');
      PRINTER_STATUS_OUTPUT_BIN_FULL    : ShowMessage('The printer''s output bin is full.');
      PRINTER_STATUS_NOT_AVAILABLE      : ShowMessage('The printer is not available for printing.');
      PRINTER_STATUS_WAITING            : ShowMessage('The printer is waiting.');
      PRINTER_STATUS_PROCESSING         : ShowMessage('The printer is processing a print job.');
      PRINTER_STATUS_INITIALIZING       : ShowMessage('The printer is initializing.');
      PRINTER_STATUS_WARMING_UP         : ShowMessage('The printer is warming up.');
      PRINTER_STATUS_TONER_LOW          : ShowMessage('The printer is low on toner.');
      PRINTER_STATUS_NO_TONER           : ShowMessage('The printer is out of toner.');
      PRINTER_STATUS_PAGE_PUNT          : ShowMessage('The printer cannot print the current page.');
      PRINTER_STATUS_USER_INTERVENTION  : ShowMessage('The printer has an error that requires the user to do something.');
      PRINTER_STATUS_OUT_OF_MEMORY      : ShowMessage('The printer has run out of memory.');
      PRINTER_STATUS_DOOR_OPEN          : ShowMessage('The printer door is open.');
      PRINTER_STATUS_POWER_SAVE         : ShowMessage('The printer is in power save mode.');
     else
       ShowMessage('The error  is unknown');
     end;

     Exit;
  end;

After this code i start the printing process and everything is in a loop for all the copies i need to print.

I am using a TSC-TPP 2410M printer and it never gives printing status although it queues the jobs. So the code never goes inside the while because i am always getting 0 printer status.

Is there any way to disable the queue or to make the app wait for the printer to stop printing and then execute the next print job? Any thoughts?

EDIT: After some suggestions from @BlurrySterk i discovered that the printer emits PRINTER_STATUS_PRINTING when the number of jobs in the queue get to 10. After printing all of them it gets ready again.

1 Answers

It seems that there are limits to the WinAPI, as mentioned in the comments.

Because the previous printer is dead now, we bought a TSC ME240. There is a programming manual for TSPL/2 commands in this link.

To solve the problem i connected the printer to the network and send TSPL/2 commands through a tcp socket.

I needed this code to get the status

  // Create TCP Client
  TCPClient := TIdTCPClient.Create();

  // Connect to server
  TCPClient.Host := PrinterIP;
  TCPClient.Port := PrinterPort;
  TCPClient.Connect();

  // Set status string
  StatusString := #27 + '!?';

  // Send command
  TCPClient.Socket.WriteLn(StatusString);

  // Check status
  PrinterStatus := TCPClient.Socket.ReadByte;

The printer is responding and the job is done. Thanks for all the effort guys/girls.

Related