Opening printer queus, managing printer queues

hi!

I am looking for a way to open my printer queue from delphi. same as opening the printer from explorer...


also looking for a way to manage printerqueu from my own application... i.e. see the queue.. and delete from a specified printer
LVL 2
joepeztAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

twinsoftCommented:
Hi, this a component that i use. It has all the info that you need in order to access the printer jobs, delete one, etc.

Have fun...


unit XSPrinterStatus;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Printers, WinSpool;

const
  imaxPrintJobs = 10000;

type
  EPrintError = class(Exception);

  TPrinterState = (psPAUSED, psERROR, psDELETING, psSPOOLING,
                   psPRINTING, psOFFLINE, psPAPEROUT, psPRINTED, psDELETED,
                   psBLOCKED_DEVQ, psUSER_INTERVENTION, psRESTART, psUNKNOWN, psOK);

  TPrinterStates = set of TPrinterState;

  TArrayJobInfo2 = array[0..iMaxPrintJobs] of TJobInfo2;

  TXSPrinterStatus = class(TComponent)
  private
    FDefaultPrinter: boolean;
    FSpoolerErrorID: integer;
    FSpoolerErrorStr: string;
    FErrorStart: integer;
    FstrPrinterName: string;
   	FhPrinter: THAndle;
	   FpPrinterInfo2: ^TPrinterInfo2;
	   FpJobStorage: ^TArrayJobInfo2;
    FNrOfJobs: DWORD;
    FErrorStates: TPrinterStates;

    function StorePrinterName: boolean;
    function GetSpoolerReady: boolean;
    function GetJobs: Boolean;
    function GetJobStatus(Index: integer): TPrinterStates;
    function GetStatusDesc(Index: integer): string;
    function QueueStatus: DWORD;
    procedure SetPrinterName(Value: string);
    function GetJobCount: integer;
    procedure SetDefaultPrinter(Value: boolean);
    function GetJobInfo(Index: integer): TJobInfo2;
  protected
  public
    property JobCount: integer read GetJobCount;
    property JobStatus[Index: Integer]: TPrinterStates read GetJobStatus;
    property StatusDesc[Index: Integer]: string read GetStatusDesc;
    property SpoolerReady: boolean read GetSpoolerReady;
    property SpoolerErrorStr: string read FSpoolerErrorStr;
    property SpoolerErrorID: integer read FSpoolerErrorID;
    property JobInfo[Index: Integer]: TJobInfo2 read GetJobInfo;
    property PrinterHandle: THandle read FhPrinter;

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure CancelPrintJob(aJobID: Integer);
    function FirstJobInError: Integer;
    function NextJobInError: Integer;
    function FindJob(Title: string): Integer;

  published
    property PrinterName: string read FstrPrinterName write SetPrinterName stored StorePrinterName;
    property ErrorStates: TPrinterStates read FErrorStates write FErrorStates default [psERROR, psOFFLINE];
    property DefaultPrinter: boolean read FDefaultPrinter write SetDefaultPrinter default true;
  end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents('System', [TXSPrinterStatus]);
end;

constructor TXSPrinterStatus.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);

 FSpoolerErrorStr := '';
 FpPrinterInfo2 := nil;
 FpJobStorage := nil;
 FErrorStates := [psERROR, psOFFLINE];

 FDefaultPrinter := true;

 SetPrinterName('');
end;

destructor TXSPrinterStatus.Destroy;
begin
 ClosePrinter(FhPrinter);
 if FpPrinterInfo2 <> nil then
  dispose(FpPrinterInfo2);

 if FpJobStorage <> nil then
		dispose(FpJobStorage);

 inherited Destroy;
end;

function TXSPrinterStatus.GetJobCount: integer;
begin
 Result := -1;

 if QueueStatus = 0 then
  Result := FNrOfJobs;
end;

function TXSPrinterStatus.QueueStatus: DWORD;
var
 cbBuf: DWORD;
 pcbBuf: pointer;
 Needed: DWORD;
 pcbNeeded: LPDWORD;
begin
 pcbBuf := @cbBuf;

 if not GetPrinter(FhPrinter, 2, Nil, 0, pcbBuf) then
  if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
   begin
    FSpoolerErrorStr := Name + ': GetPrinterQueueStatus Error: ' + IntToStr(GetLastError);
    FSpoolerErrorID := GetLastError;

    raise EPrintError.Create(FSpoolerErrorStr);
   end;

 if FpPrinterInfo2 <> nil then
  dispose(FpPrinterInfo2);

 GetMem(FpPrinterInfo2,cbBuf);
 fillChar(FpPrinterInfo2^, cbBuf, 0);

 pcbNeeded := @Needed;

 if not GetPrinter(FhPrinter, 2, FpPrinterInfo2, cbBuf, pcbNeeded) then
  begin
	 	FSpoolerErrorStr := Name + ': GetPrinterQueueStatus Error: ' + IntToStr(GetLastError);
 		FSpoolerErrorID := GetLastError;

	 	raise EPrintError.Create(FSpoolerErrorStr);
  end;

 Result := FpPrinterInfo2^.status;
 FNrOfJobs := FpPrinterInfo2^.cJobs;
end;

procedure TXSPrinterStatus.SetPrinterName(Value: string);
begin
 if (Value <> FstrPrinterName) or (Value = '') then
  begin
   FErrorStart := -1;
   if FstrPrinterName <> '' then
    ClosePrinter(FhPrinter);
   if Trim(Value) = '' then
    with Printer do
     begin
      FDefaultPrinter := true;
      Value := Printers[PrinterIndex];
     end
    else
     FDefaultPrinter := false;

   if not Openprinter(PChar(Value), FhPrinter, nil) then
    begin
   		FSpoolerErrorStr := 'OpenPrinter Error: ' + IntToStr(GetLastError);
   		FSpoolerErrorID := GetLastError;

   		raise EPrintError.Create(FSpoolerErrorStr);
    end;

   FstrPrinterName := Value;
  end;
end;

function TXSPrinterStatus.StorePrinterName: boolean;
begin
 Result := not FDefaultPrinter;
end;

function TXSPrinterStatus.GetJobStatus(Index: integer): TPrinterStates;
var
 Status: DWORD;
begin
 result := [];

 if (Index >= JobCount) or (Index < 0) then
  Exit;

 if not GetJobs then
  Exit;

 Status := FpJobStorage^[Index].status;

 if Status = 0 then
  Result := [psOK]
 else
  begin
   if (JOB_STATUS_PAUSED and Status) = JOB_STATUS_PAUSED then
    Result := Result + [psPAUSED];
   if (JOB_STATUS_ERROR and Status) = JOB_STATUS_ERROR then
    Result := Result + [psERROR];
   if (JOB_STATUS_DELETING and Status) = JOB_STATUS_DELETING then
    Result := Result + [psDELETING];
   if (JOB_STATUS_SPOOLING and Status) = JOB_STATUS_SPOOLING then
    Result := Result + [psSPOOLING];
   if (JOB_STATUS_PRINTING and Status) = JOB_STATUS_PRINTING then
    Result := Result + [psPRINTING];
   if (JOB_STATUS_OFFLINE and Status) = JOB_STATUS_OFFLINE then
    Result := Result + [psOFFLINE];
   if (JOB_STATUS_PAPEROUT and Status) = JOB_STATUS_PAPEROUT then
    Result := Result + [psPAPEROUT];
   if (JOB_STATUS_PRINTED and Status) = JOB_STATUS_PRINTED then
    Result := Result + [psPRINTED];
   if (JOB_STATUS_DELETED and Status) = JOB_STATUS_DELETED then
    Result := Result + [psDELETED];
   if (JOB_STATUS_BLOCKED_DEVQ and Status) = JOB_STATUS_BLOCKED_DEVQ then
    Result := Result + [psBLOCKED_DEVQ];
   if (JOB_STATUS_USER_INTERVENTION and Status) = JOB_STATUS_USER_INTERVENTION then
    Result := Result + [psUSER_INTERVENTION];
   if Result = [] then
    Result := [psUNKNOWN];
  end;
end;

function TXSPrinterStatus.GetJobs: Boolean;
var
 cbBuf: DWORD;
 Needed: DWORD;
begin
 GetJobs := false;

 if JobCount >= 0 then
  begin
   if not EnumJobs(FhPrinter, 0, FpPrinterInfo2^.cJobs, 2, FpJobStorage, 0, cbBuf, Needed) then
    if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
     begin
    		FSpoolerErrorStr := 'Get Jobs Error: ' + IntToStr(GetLastError);
    		FSpoolerErrorID := GetLastError;

    		raise EPrintError.Create(FSpoolerErrorStr);
     end;

   if FpJobStorage <> nil then
    dispose(FpJobStorage);

   GetMem(FpJobStorage,cbBuf);
   fillChar(FpJobStorage^, cbBuf, 0);

   if not EnumJobs(FhPrinter, 0, FpPrinterInfo2^.cJobs, 2, FpJobStorage, cbBuf, Needed, cbBuf) then
    begin
  			FSpoolerErrorStr := 'EnumJobs Error: ' + IntToStr(GetLastError);
  			FSpoolerErrorID := GetLastError;

  			raise EPrintError.Create(FSpoolerErrorStr);
    end;

   GetJobs := true;
  end;
end;

function TXSPrinterStatus.GetStatusDesc(Index: Integer): string;
var
 Status: TPrinterStates;
begin
 Status := GetJobStatus(Index);

 Result := '';

	if (psPAUSED in Status) then Result := Result + ' PAUSED';
	if (psERROR in Status) then Result := Result + ' ERROR';
	if (psDELETING in Status) then Result := Result + ' DELETING';
	if (psSPOOLING in Status) then Result := Result + ' SPOOLING';
	if (psPRINTING in Status) then Result := Result + ' PRINTING';
	if (psOFFLINE in Status) then Result := Result + ' OFFLINE';
	if (psPAPEROUT in Status) then Result := Result + ' PAPEROUT';
	if (psPRINTED in Status) then Result := Result + ' PRINTED';
	if (psDELETED in Status) then Result := Result + ' DELETED';
	if (psBLOCKED_DEVQ in Status) then Result := Result + ' BLOCKED';
	if (psUSER_INTERVENTION in Status) then Result := Result + ' USERINTERVENTION';
end;

function TXSPrinterStatus.FirstJobInError: Integer;
begin
 FErrorStart := 0;
 Result := NextJobInError;
end;

function TXSPrinterStatus.NextJobInError: Integer;
var
 i: Integer;
begin
 if FErrorStart = -1 then
  raise Exception.Create(Name + ': FirstJobInError not executed before NextJobInError');

 Result := -1;
 for i := FErrorStart to JobCount - 1 do
  if (GetJobStatus(i) * ErrorStates) <> [] then
   begin
    Result := i;
    Break;
   end;

 if Result = -1 then
  FErrorStart := JobCount+1
 else
  FErrorStart := Result + 1;
end;

function TXSPrinterStatus.GetSpoolerReady: boolean;
begin
 FSpoolerErrorStr := '';
 try
  Result := (QueueStatus = 0) and (GetJobs);
 except
  on e: EPrintError do
   Result := false;
  on e: Exception do
   raise
 end;
end;

procedure TXSPrinterStatus.SetDefaultPrinter(Value: boolean);
begin
 if Value <> FDefaultPrinter then
  begin
   FDefaultPrinter := Value;
   if FDefaultPrinter then
    SetPrinterName('');
  end;
end;

function TXSPrinterStatus.GetJobInfo(Index: integer): TJobInfo2;
begin
 if (Index < 0) or (Index >= JobCount) then
  Exit;

 Result := FpJobStorage^[Index];
end;

function TXSPrinterStatus.FindJob(Title: string): Integer;
var
 i: Integer;
begin
 Result := -1;
 if GetJobs then
  for i := 0 to JobCount - 1 do
   if (JobInfo[i].pDocument <> '') and (JobInfo[i].pDocument = Title) then
    begin
     Result := i;
     Break;
    end;
end;

procedure TXSPrinterStatus.CancelPrintJob(aJobID: Integer);
var
 aJob: TJobInfo2;
begin
 aJob := GetJobInfo(aJobID);
 SetJob(FhPrinter, aJob.JobId, 0, nil, JOB_CONTROL_DELETE);
end;

end.

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
joepeztAuthor Commented:
wow really, this is usefull too, if you can figure out how to also open my printer in explorer I double points :-)
0
twinsoftCommented:
What do you mean ?

"how to also open my printer in explorer"
0
joepeztAuthor Commented:
in explorer, you can go to printers, there you see all the installed printers.. you double click on it, and can open the queue from there also..

I just want to open this programmically
0
twinsoftCommented:
Hi, call this function with the name on the printer...

And please give some more points. As you can see from other threads, a question like this gets at least 500 points....

Uses ShlObj, ActiveX, ShellAPI;

function TForm1.OpenThisPrinter(PrinterName: String): Boolean;
var
 Allocator: IMalloc;
 PrinterItemIDList:  pItemIDList;
 ShellExecuteInfo :  TShellExecuteInfo;
begin
 Result := False;
 if CoGetMalloc(MEMCTX_TASK, Allocator) = S_OK then
  begin
   PrinterItemIDList := GetThisPrinter(PrinterName, Allocator);
   try
    if PrinterItemIDList = nil then
     Result := False
    else
     begin
      ZeroMemory(@ShellExecuteInfo, SizeOf(TShellExecuteInfo));
      with ShellExecuteInfo do
       begin
        cbSize := SizeOf(TShellExecuteInfo);
        fMask := SEE_MASK_INVOKEIDLIST OR SEE_MASK_FLAG_NO_UI;
        lpIDList := PrinterItemIDlist;
        nShow := SW_SHOWDEFAULT;
       end;

      ShellExecuteEx(@ShellExecuteInfo);
      Result := True;
     end;
   finally
    Allocator.Free(PrinterItemIDList)
   end;
  end;
end;
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.