Solved

Detecting Printer Status ... Help?

Posted on 1998-10-05
15
1,159 Views
Last Modified: 2008-02-20
Hi,  I require a piece of code or a function call that will allow me to detect whether a printer is online or offline.  I am writing a restaurant system and wish to redirect printing to another printer in the event of the printer being offline.  Please assist
0
Comment
Question by:Tazi
  • 7
  • 4
  • 3
  • +1
15 Comments
 
LVL 8

Expert Comment

by:ZifNab
ID: 1341845
Hi,

It's not so practical as you think it would... Imagine this. You want to print something to a certain printer. In the queue there is one article of 200 pages before you, but the printer is still printing, so you send your paper to the printer... After a while The printer stops at 175 papers... no more paper.... Suppose the user already closed your application... What now?

Let the spooler handle such things, it's made for such a thing.

If you use AssignFile (very simple printing)... You could use the try except end ...

Regards, Zif.
0
 
LVL 1

Expert Comment

by:Gerhard100198
ID: 1341846
I found the following in the SWAG databases, hopefully some of it will be usefull to you.
A lot of it seems to be TP 6.0 or TP 7.0 codebut you might still be able to use it.

I've put everything I could find in here. The =========== line seperates the different messages I could locate on this subject.

===================================================
DS>Does anyone know how you can check from Turbo Pascal that the
DS>printer is turned on so that you won't get a device error that
DS>will crash a program?  I can't find anything about this.

Program  Printer_Status;
Uses Dos;
Function PrinterOnLine : Boolean;
  Const
    PrnStatusInt  : Byte = $17;    (*  Dos interrupt *)
    StatusRequest : Byte = $02;    (*  Interrupt Function Call *)

    PrinterNum    : Word = 0;  { 0 for LPT1, 1 for LPT2, etc. }
  Var
    Regs : Registers ;         { Type is defined in Dos Unit }

    Begin  (* PrinterOnLine*)
      Regs.AH := StatusRequest;
      Regs.DX := PrinterNum;
      Intr(PrnStatusInt, Regs);
      PrinterOnLine := (Regs.AH and $80) = $80;
    End;

Begin (* Main Program *)
  If PrinterOnLine Then
    Writeln('Ready To Print')
  Else
    Writeln('Please check the printer!');
End.
======================================================
(The following is Pascal code)

PK>    Any suggestions as to how I can check if a printer is online
PK>and/or ready would be appreciated.

    Interrupt 17h service 02h returns printer status flags. We are
interested in three:

    bit 7 = 1   Ready
    bit 5 = 1   Out of paper
    bit 3 = 1   I/O error


    Bit 7 should be 1 and bits 5, 3 -- 0. You can use the following
BASM routine to check it:

const
  pnLPT1    = 0;
  pnLPT2    = 1;
  pnLPT3    = 2;

function PrinterReady(PN: word): boolean; assembler;
asm
    mov     dx, PN              {printer number goes in DX}
    mov     ah, 02h
    int     17h                 {int. 17h service 02h}
    xor     al, al              {assume false}
    and     ah, 10101000b       {clear all other bits}
    cmp     ah, 10000000b       {ready & not out of paper or error?}
    jne     @Done               {no -- leave result false}
    inc     ax                  {yes -- change to true}
@Done:
end;
============================================
PROGRAM PRINTCHK;

uses crt,dos,printer;
const
  lpt1=0;
  lpt2=1;
  lpt3=2;

  PrnReady = $90;
  OffLine = $00;
  OffLine2 = $10;             {NEW LINE}
  PaperOut = $20;
  PaperOut2 = $30;            {NEW LINE}
  HookedButOff = $80;         {NEW LINE}
  NoConnect = $B0;            {MODIFIED LINE}

  {NOCONNECT = $30 FOR SOME COMPUTERS BY STU}

  Function ChkPrinter(Printer:Word) :Word;
  Var Regs:Registers;

  Begin
    Regs.AH:=2;
    Regs.DX:=Printer;
    Intr($17,regs);
    ChkPrinter:=Regs.AH
  end;

  Procedure PrinterError(ErrorCode:BYTE);  ;NEW


  VAR
    C : BYTE;



  Begin
   ErrorCode := ErrorCode and $B0;       {NEW LINE}

   C := ERRORCODE SHL 6   {ALWAYS MEANS NOTHING CONNECTED}

   IF C > 0 THEN ERRORCODE = $B0; {ELEMINATES NO LPT3 AND NOTHING CONNECTED}


   Case ErrorCode of
    NoConnect           : WriteLn('Printer not connected');
    Offline,OffLine2    : WriteLn('Printer off line');     {Modified}
    PaperOut,PaperOut2  : WriteLn('Printer out of paper'); {Modified}
    HookedButOff        : WriteLn('Printer connected but turned off'); {New}
   else
    WriteLn('Printer error code: ',ErrorCode);
   end
  end;

  procedure TryPrinter;
  Begin
   {$I-}
   WriteLn(Lst,'Check Printer'+#12);
   {$I+}
   WriteLn(IOResult)
  End;

  Begin
   ClrScr;
   {TryPrinter;}
   If ChkPrinter(LPT1) = PrnReady then
    Writeln('Printer is Ready')
   else
    PrinterError(ChkPrinter(LPT1))
  end.
==============================================

{ Untested On }

   FUNCTION PrinterNotReady : BOOLEAN;
   VAR Regs : REGISTERS;
   BEGIN
      PrinterNotReady := TRUE;
      FILLCHAR(Regs, SIZEOF(Regs), 00);
      WITH Regs DO BEGIN
         AX := $0200;
         DX := 0; { LPT1 = 0, LPT2 = 1 }
      END;
      Intr($17, Regs);
      IF Regs.AX AND $4000 = 0 THEN BEGIN
         IF Regs.AX AND $1000 <> 0 THEN PrinterNotReady := FALSE;
      END;
   END;

==========================
{$S-,R-,V-,I-,N-,B-,F-}

{$IFNDEF Ver40}
{Allow overlays}
{$F+,O-,X+,A-}
{$ENDIF}

{$DEFINE AssignLstDevice}

UNIT Printer;

INTERFACE

CONST

  fmClosed = $D7B0;               { magic numbers for Turbo }
  fmInput = $D7B1;
  fmOutput = $D782;
  fmInOut = $D7B3;

  IO_Invalid = $FC;               { invalid operation eg. attempt to write }
  { to a file opened in fmInput mode       }

  LPTNames : ARRAY [0..2] OF STRING [4] = ('LPT1', 'LPT2', 'LPT3');

  LPTPort : BYTE = 0;

VAR
  Lst : TEXT;                     { for source compatability with TP3 }

FUNCTION GetROMPrinterStatus (LPTNo : WORD) : BYTE;
  { status of LPTNo via ROM BIOS int 17h func 2h }
  INLINE (
    $5A /                         {  pop     DX    ; get printer number}
    $B4 / $02 /                   {  mov     AH,02 ; set AH for BIOS int 17h function 0}
    $CD / $17 /                   {  int     $17   ; do an int 17h}
    $86 / $E0);                   {  xchg    AL,AH ; put byte result in AL}

FUNCTION DoInt17 (Ch : CHAR; LPTNo : WORD) : BYTE;
  { send a character to LPTNo via ROM BIOS int 17h func 0h }
  INLINE (
    $5A /                         {  pop     DX    ; get printer number}
    $58 /                         {  pop     AX    ; get char}
    $B4 / $00 /                   {  mov     AH,00 ; set AH for BIOS int 17h function 0}
    $CD / $17 /                   {  int     $17   ; do an int 17h}
    $86 / $E0);                   {  xchg    AL,AH ; put byte result in AL}

PROCEDURE AssignLst (VAR F : TEXT; LPTNumber : WORD);
  { like Turbo's assign, except associates Text variable with one of the LPTs }

PROCEDURE OutputToFile (FName : STRING);
  {redirect printer output to file }

FUNCTION  PrinterStatus (LPTNum : BYTE) : BYTE;

FUNCTION  Printer_OK : BOOLEAN;

PROCEDURE SelectPrinter (LPTNum : BYTE);

PROCEDURE ResetPrinter;           { only resets printer 0 }

IMPLEMENTATION

TYPE
  TextBuffer = ARRAY [0..127] OF CHAR;

  TextRec = RECORD
              Handle   : WORD;
              Mode     : WORD;
              BufSize  : WORD;
              Private  : WORD;
              BufPos   : WORD;
              BufEnd   : WORD;
              BufPtr   : ^TextBuffer;
              OpenFunc : POINTER;
              InOutFunc : POINTER;
              FlushFunc : POINTER;
              CloseFunc : POINTER;
              { 16 byte user data area, I use 4 bytes }
              PrintMode : WORD;   { not currently used}
              LPTNo : WORD;       { LPT number in [0..2] }
              UserData : ARRAY [1..12] OF CHAR;
              Name : ARRAY [0..79] OF CHAR;
              Buffer : TextBuffer;
            END;
CONST
  LPTFileopen : BOOLEAN = FALSE;

VAR
  LPTExitSave : POINTER;

  PROCEDURE Out_Char (Ch : CHAR; LPTNo : WORD; VAR ErrorCode : INTEGER);
    { call macro to send char to LPTNo.  If bit 4, the Printer Selected bit }
    { is not set upon return, it is assumed that an error has occurred.     }

  BEGIN
    ErrorCode := DoInt17 (Ch, LPTNo);
    IF (ErrorCode AND $10) = $10 THEN { if bit 4 is set }
      ErrorCode := 0              { no error }
      { if bit 4 is not set, error is passed untouched and placed in IOResult }
  END;

  FUNCTION LstIgnore (VAR F : TextRec) : INTEGER;
    { A do nothing, no error routine }
  BEGIN
    LstIgnore := 0                { return 0 for IOResult }
  END;

  FUNCTION LstOutput (VAR F : TextRec) : INTEGER;
    { Send whatever has accumulated in the Buffer to int 17h   }
    { If error occurs, return in IOResult.  See Inside Turbo   }
    { Pascal chapter of TP4 manual for more info on TFDD       }
  VAR
    I : WORD;
    ErrorCode : INTEGER;

  BEGIN
    LstOutput := 0;
    WITH F DO BEGIN
      FOR I := 0 TO PRED (BufPos) DO BEGIN
        Out_Char (BufPtr^ [I], LPTNo, ErrorCode); { send each char to printer }
        IF ErrorCode <> 0 THEN BEGIN { if error }
          LstOutput := ErrorCode; { return errorcode in IOResult }
          EXIT                    { return from function }
        END
      END;
      BufPos := 0
    END;
  END;

  PROCEDURE AssignLst (VAR F : TEXT; LPTNumber : WORD);
    { like Turbo's assign, except associates Text variable with one of the LPTs }

  BEGIN
    WITH TextRec (F) DO
      BEGIN
        Mode := fmClosed;
        BufSize := SIZEOF (Buffer);
        BufPtr := @Buffer;
        OpenFunc := @LstIgnore;   { you don't open the BIOS printer functions }
        CloseFunc := @LstIgnore;  { nor do you close them }
        InOutFunc := @LstOutput;  { but you can Write to them }
        FlushFunc := @LstOutput;  { and you can WriteLn to them }
        LPTNo := LPTNumber;       { user selected printer num (in [0..2]) }
        MOVE (LPTNames [LPTNumber], Name, 4); { set name of device }
        BufPos := 0;              { reset BufPos }
      END;
  END;

  PROCEDURE OutputToFile (FName : STRING);
  BEGIN
    ASSIGN (Lst, FName);
    REWRITE (Lst);
    LPTFileopen := TRUE;
  END;

  FUNCTION PrinterStatus (LPTNum : BYTE) : BYTE;
  VAR
    Status : BYTE;
  BEGIN
    Status := GetROMPrinterStatus (LPTNum);
    IF (Status AND $B8) = $90 THEN
      PrinterStatus := 0          {all's well}
    ELSE IF (Status AND $20) = $20 THEN
      PrinterStatus := 1          {no Paper}
    ELSE IF (Status AND $10) = $00 THEN
      PrinterStatus := 2          {off line}
    ELSE IF (Status AND $80) = $00 THEN
      PrinterStatus := 3          {busy}
    ELSE IF (Status AND $08) = $08 THEN
      PrinterStatus := 4;         {undetermined error}
  END;

  FUNCTION Printer_OK : BOOLEAN;
  VAR
    Retry : BYTE;
  BEGIN
    Retry := 0;
    WHILE (PrinterStatus (LPTPort) <> 0) AND (Retry < 255) DO INC (Retry);
    Printer_OK := (PrinterStatus (LPTPort) = 0);
  END;                            {PrinterReady}

  PROCEDURE SelectPrinter (LPTNum : BYTE);
  BEGIN
    IF (LPTNum >= 0) AND (LPTNum <= 3) THEN
      LPTPort := LPTNum;
    AssignLst (Lst, LPTPort);      { set up turbo 3 compatable Lst device }
    REWRITE (Lst);
  END;

  PROCEDURE ResetPrinter;
  VAR
    address : INTEGER ABSOLUTE $0040 : $0008;
    portno, DELAY : INTEGER;
  BEGIN
    portno := address + 2;
    Port [portno] := 232;
    FOR DELAY := 1 TO 2000 DO {nothing} ;
    Port [portno] := 236;
  END;                            {ResetPrinter}

  PROCEDURE LptExitHandler; FAR;
  BEGIN
    IF LPTFileopen THEN CLOSE (Lst);
    ExitProc := LPTExitSave;
  END;

BEGIN

  LPTExitSave := ExitProc;
  ExitProc := @LptExitHandler;

  {$IFDEF AssignLstDevice}

  LPTPort := 0;
  AssignLst (Lst, LPTPort);        { set up turbo 3 compatable Lst device }
  REWRITE (Lst);

  {$ENDIF}

END.
===========================================
Unit Myprint;
{$D-,I-,S-}
Interface

Uses Dos;

Var
  Prt        : Array[1..2] of Text;
  Lst        : Text Absolute Prt;

Function PrinterStatus(p: Byte): Byte;
Function PrinterReady(Var b : Byte; p: Byte): Boolean;

Implementation

Procedure RawMode(Var L);       { make sure that device is in raw mode }
  Var
    regs : Registers;
  begin
    With regs do begin
      bx   := TextRec(L).Handle;         { place the File handle in bx }
      ax   := $4400;           { setup For Function $44 sub-Function 0 }
      MSDos(regs);                              { execute Dos Function }
      dl   := dl or $20;                            { bit 5 = raw mode }
      dh   := 0;                                      { set dh to zero }
      ax   := $4401;           { setup For Function $44 sub-Function 1 }
      MSDos(regs)                               { execute Dos Function }
    end; { With }
  end; { RawMode }

Function PrinterStatus(p: Byte): Byte;
   { Returns the Printer status. LPT1=p=1, LPT2=p=2 }
   Var regs   : Registers; { from the Dos Unit                         }
   begin
     With regs do begin
       dx := p - 1;        { The Printer number                        }
       ax := $0200;        { The Function code For service wanted      }
       intr($17,regs);     { $17= ROM bios int to return Printer status}
       PrinterStatus := ah;{ Bit 0 set = timed out                     }
     end;                  {     1     = unused                        }
   end;                    {     2     = unused                        }
                           {     3     = I/O error                     }
                           {     4     = Printer selected              }
                           {     5     = out of paper                  }
                           {     6     = acknowledge                   }
                           {     7     = Printer not busy              }

Function PrinterReady(Var b : Byte; p: Byte): Boolean;
  begin
    b := PrinterStatus(p);
    PrinterReady := (b = $90)         { This may Vary between Printers }
  end;

begin
  assign(Prt[1],'LPT1');
  reWrite(Prt[1]);
  RawMode(Prt[1]);
  assign(Prt[2],'LPT2');
  reWrite(Prt[2]);
  RawMode(Prt[2]);
end.

==================================================
{Your're in luck, I just got a new Printer and started writing routines to
control it (TFDD etc..). These are probably the most important ones:



 note: This routines are not throughly tested on Various Printers.
       Thus it may of may not work on your Type of Printer.
       But, as a rule, experiment With it and have fun............}

Uses
  Dos;

Functio PrinterOutofPaper( Port : Byte): Boolean;
Var
  Regs : Registers;
begin
  Regs.AH := $02;
  Regs.DX := Port;          { 0=LPT1,  1=LPT2,  2=LPT3 }
  Intr($17, Regs);          { Print Service Please }
  PrinterOutofPaper := (Regs.AH and $20 = $20)
end;

Function PrinterReady( Port : Byte): Boolean;
Var
  Regs : Registers;
begin
  With Regs Do
    begin
      AH := $02;
      DX := Port;          { 0=LPT1,  1=LPT2,  2=LPT3 }
      Intr($17, Regs)
      PrinterReady := (AH and $80 = $80) and       { Printer Busy?   }
                      (AH and $10 = $10) and       { Printer Online? }
                      (AH and $08 = $00)           { Printer Error?  }
     end
end;

Procedure PrintChar(Port: Byte; Ch: Char);
Var
  Regs : Registers;
begin
  With Regs Do
    begin
      AL := ord(Ch);             { Char to print            }
      DX := Port;                { 0=LPT1,  1=LPT2,  2=LPT3 }
      AH := $00;                 { Print Char Service       }
      Intr($17, Regs);           { Call Bios                }
    end
end;

Procedure BootPrinter( Port: Byte);
 { Initializes IBM- or EPSON- Compatible Printer  }
 { Other Printers may not understand this command }
 { and may produce unwanted results               }
Var
  Regs : Registers;
begin
  Regs.DX := Port;                { 0=LPT1,  1=LPT2,  2=LPT3 }
  Regs.AH := $01;
  Intr($17, Regs)
end;
=====================================
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1341847
I don't know about this... it may work, but... I don't think it will in NT, still in Win98?

Still, why do you need it?
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1341848
you cannot use the registers that way..you need to use 'em like so..

function Add(a,b : Integer):Integer;
begin
      asm
            mov eax, a
            add eax, b
            mov result, eax
      end
end;

Which will add the two integers and return them... You cannot use this though,,,
function add(a,b ; integer):Integer;
var
  Reg : Registers;
begin
      Reg.eax := a;
      Reg.eax := Reg.eax + b;
      Result := Reg.eax;
end;

This is not allowed as Delphi doesn't have a type Registers, and only TP7 supported that... I don't even know if Win98 supports Assembler and also not sure if WinNT supports that too...

Regards,
Viktor Ivanov
0
 

Author Comment

by:Tazi
ID: 1341849
Gerhard..

Thanks a million for the code, but I am sorry to say or
rather sorry that I failed to mention that I need a piece of code for
a Windows Based Program and not a Dos system.  The code that you gave
me uses Dos, however, i am still working on it and will keep you
informed.

If you have a windows piece of code please let me know...
The system is Window's 95/98 compliant

- - - LET ME GIVE U AN EXAMPLE
 am writing a restaurant system.  I will give u a scenario.  Assume that the restaurant will be set up using 2 workstations,
Workstation 1 and Workstation 2, as well as a Server.  Workstation 1 has a local printer attached to it which will be used to print bills for the customers.  Workstation 2 shares this printer over the network.  Workstation 1 also has a Kitchen Printer attached to it, and once again Workstation 2 will share this printer over the network.  Workstation 2 however, has the Bar Printer attached to it.  This printer will be available for use over the network.

I print an order to the Kitchen, the printer is offline so the order does not print..I want my system to detect that the printer is
in-operable and printing must be diverted to either the BAR Printer or it should print locally to the Bill Printer depending on the choice made by the manager.


Thanks alot

Tazi....

 
0
 

Author Comment

by:Tazi
ID: 1341850
Gerhard..

Thanks a million for the code, but I am sorry to say or
rather sorry that I failed to mention that I need a piece of code for
a Windows Based Program and not a Dos system.  The code that you gave
me uses Dos, however, i am still working on it and will keep you
informed.

If you have a windows piece of code please let me know...
The system is Window's 95/98 compliant

- - - LET ME GIVE U AN EXAMPLE
 am writing a restaurant system.  I will give u a scenario.  Assume that the restaurant will be set up using 2 workstations,
Workstation 1 and Workstation 2, as well as a Server.  Workstation 1 has a local printer attached to it which will be used to print bills for the customers.  Workstation 2 shares this printer over the network.  Workstation 1 also has a Kitchen Printer attached to it, and once again Workstation 2 will share this printer over the network.  Workstation 2 however, has the Bar Printer attached to it.  This printer will be available for use over the network.

I print an order to the Kitchen, the printer is offline so the order does not print..I want my system to detect that the printer is
in-operable and printing must be diverted to either the BAR Printer or it should print locally to the Bill Printer depending on the choice made by the manager.


Thanks alot

Tazi....

 
0
 
LVL 1

Accepted Solution

by:
Gerhard100198 earned 200 total points
ID: 1341851
I've found a component on the Delphi Super Page. I played around with it, modified it slightly and wrote a little demo for it. I'll post all the source code here since it's not too long. There are comments at the beginning of the source files which needs to be read.

PrinterEx component - PrinterEx.Pas files start
<----------------------------------------------------------------------------------------->
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Autor       : Pasha A. Poskraykoff
Module      : PrinterEx.pas
Description : More Info About Printers in your system and Jobs
Creation    : 11.09.98
Mail me     : pap@savva.ru
Version     : 2.0

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
(*This is a component which I found on the Delphi super page.

I've inclided the inof file since this is somenbody else's work.

I've made a couple of modifications specifically to try and get a more defined
printer status under NT. The code works fine but under NT the printer status always returns
as 0. If the Win95 code is used to determing the printer status under NT only paused and
being deleted states will be returned (these are returned correctly).

Under Win95 I could only get it to return a status to indicate that the printer was paused.
When taking the printer off line or switching it off the status returned was 0 in both cases.

It seems I do not understand the satus property or something is being done wrong.

Gerhard van Rensburg
gerhardv@email.com

[DSP upload]
Filename=PrinterEx.pas
Replacements=
Version=2.0
FileURL=
Description=The component that included all info about system printers, use PRINTER_INFO_2 structure
Delphi 1.0=N
Delphi 2.0=Y
Delphi 3.0=Y
C++Builder 1.0=Y
File Status=Freeware
Full Source=Source code aviable on home page
Category=System
Note=
Additional info=

[Uploader]
Author name=Pasha A. Poskryakoff
Author E-mail=pap@savva.ru
Author URL=http://www.homepage.techno.ru/pap*)

unit PrinterEx;

interface

uses
  Windows, Forms, SysUtils, Classes, Winspool;

type
  EInvalidIndex = class(Exception);

  TPrinterInfo = record
    ServerName: String; PrinterName    : String; ShareName     : String;
    PortName  : String; DriverName     : String; Comment       : String;
    Location  : String; SepFile        : String; PrintProcessor: String;
    Datatype  : String; Parameters     : String; Attributes    : DWORD ;
    Priority  : DWORD ; DefaultPriority: DWORD ; StartTime     : DWORD ;
    UntilTime : DWORD ; Status         : DWORD ; Jobs          : DWORD ;
    AveragePPM: DWORD ;
  end;
  PPrinterInfo = ^TPrinterInfo;

  TJobInfo = record
    JobId       : DWORD      ; PrinterName   : String; MachineName : String;
    UserName    : String     ; Document      : String; NotifyName  : String;
    Datatype    : String     ; PrintProcessor: String; Parameters  : String;
    DriverName  : String     ; dStatus       : String; dwStatus    : DWORD ;
    Priority    : DWORD      ; Position      : DWORD ; StartTime   : DWORD ;
    UntilTime   : DWORD      ; TotalPages    : DWORD ; Size        : DWORD ;
    Submitted   : TSystemTime; Time          : DWORD ; PagesPrinted: DWORD ;
  end;
  PJobInfo = ^TJobInfo;

  TPrinterEx = class(TComponent)
  private
    { Private declarations }
    FPrinters: TList;
    FJobs    : TList;

    function  GetPrinter    (Index: Integer): TPrinterInfo;
    function  GetPrinterProp(Index: Integer): Boolean;
    function  GetPrintersCount              : Integer;

    procedure GetJobs(ID: THandle);
    function  GetJobInfo(Index: Integer): TJobInfo;
    function  GetJobsCount              : Integer;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy;                    override;

    procedure UpdatePrinters;
    function  UpdateJobs(Index: Integer): Boolean;

    property Printer        [Index: Integer]: TPrinterInfo read GetPrinter      ;
    property PrinterProperty[Index: Integer]: Boolean      read GetPrinterProp  ;
    property PrintersCount                  : Integer      read GetPrintersCount;

    property Job            [Index: Integer]: TJobInfo     read GetJobInfo      ;
    property JobsCount                      : Integer      read GetJobsCount    ;

  published
    { Published declarations }
  end;

procedure Register;

implementation

constructor TPrinterEx.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FPrinters := TList.Create;
  FJobs     := TList.Create;
  FPrinters.Capacity := 30;
  FJobs    .Capacity := 30;

  UpdatePrinters;
  UpdatePrinters;
end;

destructor TPrinterEx.Destroy;
Var
  I: Integer;
begin
  for I := 0 to FPrinters.Count -1 do Dispose(FPrinters[I]);
  for I := 0 to FJobs    .Count -1 do Dispose(FJobs    [I]);

  FPrinters.Clear;
  FJobs    .Clear;
  FPrinters.Destroy;
  FJobs    .Destroy;
  inherited;
end;

procedure TPrinterEx.UpdatePrinters;
Var
  pcbNeeded  ,
  pcReturned : DWORD;
  Buffer     ,
  PrinterInfo: PChar;
  I          : Integer;
  PPrinter   : PPrinterInfo;
begin

  if FPrinters.Count > 0 then begin
     for I :=0 to FPrinters.Count -1 do Dispose(FPrinters[I]);
     FPrinters.Clear;
  end;

  EnumPrinters(PRINTER_ENUM_LOCAL, nil, 2, nil, 0, pcbNeeded, pcReturned);
  GetMem(Buffer, pcbNeeded);
  EnumPrinters(PRINTER_ENUM_LOCAL, nil, 2, PByte(Buffer), pcbNeeded, pcbNeeded, pcReturned);
  PrinterInfo := Buffer;
  for I := 0 to pcReturned -1 do
    with PPrinterInfo2(PrinterInfo)^ do begin

      New(PPrinter);

      PPrinter^.ServerName     := StrPas(pServerName    );
      PPrinter^.PrinterName    := StrPas(pPrinterName   );
      PPrinter^.ShareName      := StrPas(pShareName     );
      PPrinter^.PortName       := StrPas(pPortName      );
      PPrinter^.DriverName     := StrPas(pDriverName    );
      PPrinter^.Comment        := StrPas(pComment       );
      PPrinter^.Location       := StrPas(pLocation      );
      PPrinter^.SepFile        := StrPas(pSepFile       );
      PPrinter^.PrintProcessor := StrPas(pPrintProcessor);
      PPrinter^.Datatype       := StrPas(pDatatype      );
      PPrinter^.Parameters     := StrPas(pParameters    );
      PPrinter^.Attributes     := Attributes             ;
      PPrinter^.Priority       := Priority               ;
      PPrinter^.DefaultPriority:= DefaultPriority        ;
      PPrinter^.StartTime      := StartTime              ;
      PPrinter^.UntilTime      := UntilTime              ;

                  {<09/10/1998 11:19:38> -> Gerhard van Rensburg <- Added PPrinter^.Status := PPrinterInfo6(PrinterInfo)^.dwStatus
      to try and get a more detailed description of the printer status under NT.
      Since PPrinterInfo6 works only under NT I had to build in the check}
      If Win32Platform = VER_PLATFORM_WIN32_NT then
        PPrinter^.Status         := PPrinterInfo6(PrinterInfo)^.dwStatus
      else
            PPrinter^.Status         := Status               ;

      PPrinter^.Jobs           := cJobs                  ;
      PPrinter^.AveragePPM     := AveragePPM             ;

      FPrinters.Add(Pointer(PPrinter));

      Inc(PrinterInfo, SizeOf(TPrinterInfo2));
    end;
  FreeMem(Buffer);
end;

function TPrinterEx.GetPrinter(Index: Integer): TPrinterInfo;
var
  PPrinter: PPrinterInfo;
begin
  if (Index > FPrinters.Count) and (FPrinters.Count <> 0) then begin
    raise EInvalidIndex.Create(Format(LoadStr(65451), [Index]));
    Exit;
  end;
  if FPrinters.Count <> 0 then begin
    PPrinter := FPrinters.Items[Index];
    with Result do begin
      ServerName     := PPrinter^.ServerName     ;
      PrinterName    := PPrinter^.PrinterName    ;
      ShareName      := PPrinter^.ShareName      ;
      PortName       := PPrinter^.PortName       ;
      DriverName     := PPrinter^.DriverName     ;
      Comment        := PPrinter^.Comment        ;
      Location       := PPrinter^.Location       ;
      SepFile        := PPrinter^.SepFile        ;
      PrintProcessor := PPrinter^.PrintProcessor ;
      Datatype       := PPrinter^.Datatype       ;
      Parameters     := PPrinter^.Parameters     ;
      Attributes     := PPrinter^.Attributes     ;
      Priority       := PPrinter^.Priority       ;
      DefaultPriority:= PPrinter^.DefaultPriority;
      StartTime      := PPrinter^.StartTime      ;
      UntilTime      := PPrinter^.UntilTime      ;
      Status         := PPrinter^.Status         ;
      Jobs           := PPrinter^.Jobs           ;
      AveragePPM     := PPrinter^.AveragePPM     ;
    end;
  end;
end;

function TPrinterEx.GetPrintersCount: Integer;
begin
  Result := FPrinters.Count;
end;

function TPrinterEx.GetPrinterProp(Index: Integer): Boolean;
Var
  hPrinter: THandle;
  PI      : TPrinterInfo;
begin
  Result := False;
  PI     := Self.GetPrinter(Index);
  if OpenPrinter(PChar(PI.PrinterName), hPrinter, nil) then begin
    PrinterProperties((Owner As TForm).Handle, hPrinter);
    ClosePrinter(hPrinter);
    Result := True;
  end;
end;

function TPrinterEx.UpdateJobs(Index: Integer): Boolean;
Var
  hPrinter: THandle;
  PI      : TPrinterInfo;
begin
  Result := False;
  PI     := Self.GetPrinter(Index);
  if OpenPrinter(PChar(PI.PrinterName), hPrinter, nil) then begin
    GetJobs(hPrinter);
    ClosePrinter(hPrinter);
    Result := True;
  end;
end;

procedure TPrinterEx.GetJobs(ID: THandle);
Var
  pcbNeeded ,
  pcReturned: DWORD;
  Buffer    ,
  JobsInfo  : PChar;
  I         : Integer;
  PJobs     : PJobInfo;
begin

  if FJobs.Count > 0 then begin
     for I :=0 to FJobs.Count -1 do Dispose(FJobs[I]);
     FJobs.Clear;
  end;

  EnumJobs(ID, 0, High(Integer), 2, nil, 0, pcbNeeded, pcReturned);
  GetMem(Buffer, pcbNeeded);
  EnumJobs(ID, 0, High(Integer), 2, PByte(Buffer), pcbNeeded, pcbNeeded, pcReturned);
  JobsInfo := Buffer;
  for I := 0 to pcReturned -1 do
    with PJobInfo2(JobsInfo)^ do begin

      New(PJobs);

      PJobs^.JobId          := JobId                  ;
      PJobs^.PrinterName    := StrPas(pPrinterName)   ;
      PJobs^.MachineName    := StrPas(pMachineName)   ;
      PJobs^.UserName       := StrPas(pUserName)      ;
      PJobs^.Document       := StrPas(pDocument)      ;
      PJobs^.NotifyName     := StrPas(pNotifyName)    ;
      PJobs^.Datatype       := StrPas(pDatatype)      ;
      PJobs^.PrintProcessor := StrPas(pPrintProcessor);
      PJobs^.Parameters     := StrPas(pParameters)    ;
      PJobs^.DriverName     := StrPas(pDriverName)    ;
      PJobs^.dStatus        := StrPas(pStatus)        ;
      PJobs^.dwStatus       := Status                 ;
      PJobs^.Priority       := Priority               ;
      PJobs^.Position       := Position               ;
      PJobs^.StartTime      := StartTime              ;
      PJobs^.UntilTime      := UntilTime              ;
      PJobs^.TotalPages     := TotalPages             ;
      PJobs^.Size           := Size                   ;
      PJobs^.Submitted      := Submitted              ;
      PJobs^.Time           := Time                   ;
      PJobs^.PagesPrinted   := PagesPrinted           ;

      FJobs.Add(Pointer(PJobs));

      Inc(JobsInfo, SizeOf(TJobInfo2));
    end;
  FreeMem(Buffer);
end;

function TPrinterEx.GetJobInfo(Index: Integer): TJobInfo;
var
  PJob: PJobInfo;
begin
  if (Index > FPrinters.Count) and (FPrinters.Count <> 0) then begin
    raise EInvalidIndex.Create(Format(LoadStr(65451), [Index]));
    Exit;
  end;
  if FJobs.Count <> 0 then begin
    PJob := FJobs.Items[Index];
    with Result do begin
      JobId          := PJob^.JobId         ;
      PrinterName    := PJob^.PrinterName   ;
      MachineName    := PJob^.MachineName   ;
      UserName       := PJob^.UserName      ;
      Document       := PJob^.Document      ;
      NotifyName     := PJob^.NotifyName    ;
      Datatype       := PJob^.Datatype      ;
      PrintProcessor := PJob^.PrintProcessor;
      Parameters     := PJob^.Parameters    ;
      DriverName     := PJob^.DriverName    ;
      dStatus        := PJob^.dStatus       ;
      dwStatus       := PJob^.dwStatus      ;
      Priority       := PJob^.Priority      ;
      Position       := PJob^.Position      ;
      StartTime      := PJob^.StartTime     ;
      UntilTime      := PJob^.UntilTime     ;
      TotalPages     := PJob^.TotalPages    ;
      Size           := PJob^.Size          ;
      Submitted      := PJob^.Submitted     ;
      Time           := PJob^.Time          ;
      PagesPrinted   := PJob^.PagesPrinted  ;
    end;
  end;
end;

function TPrinterEx.GetJobsCount: Integer;
begin
  Result := FJobs.Count;
end;

procedure Register;
begin
  RegisterComponents('PAP', [TPrinterEx]);
end;
end.
<----------------------------------------------------------------------------------------->
PrinterEx component - PrinterEx.Pas file end

PrinterEx component Demo - Unti1.Pas file start
<----------------------------------------------------------------------------------------->
(*I've written this little program as a demo for the PrinterEx component written
by asha A. Poskraykoff. It's not fully commencted but easy enough to understand.

Gerhard van Rensburg - gerhardvr@email.com*)

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, PrinterEx, WinSpool, ExtCtrls;

type
  TForm1 = class(TForm)
    PrinterEx1: TPrinterEx;
    Panel2: TPanel;
    Panel3: TPanel;
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
      x: TPrinterInfo;
  y: TJobInfo;
  I, J: Integer;
begin
      Memo1.clear;

  With Memo1 do begin
        PrinterEx1.UpdatePrinters;
        for I := 0 to PrinterEx1.PrintersCount - 1 do begin
              PrinterEx1.UpdatePrinters;
              x := PrinterEx1.Printer[I];
      Lines.Add('Server name: ' + x.ServerName);
      Lines.Add('Printer name: ' + x.PrinterName);
      Lines.Add('Share name: ' + x.ShareName);
      Lines.Add('Port name: ' + x.PortName);
      Lines.Add('Driver name: ' + x.DriverName);
      Lines.Add('Comment: ' + x.Comment);
      Lines.Add('Location: ' + x.Location);
      Lines.Add('Sep file: ' + x.SepFile);
      Lines.Add('Print processor: ' + x.PrintProcessor);
      Lines.Add('Datatype: ' + x.Datatype);
      Lines.Add('Parameter: ' + x.Parameters);
      Lines.Add('Attributes: ' + IntToStr(x.Attributes));
      Lines.Add('Priority: ' + IntToStr(x.Priority));
      Lines.Add('Default Priority: ' + IntToStr(x.DefaultPriority));
      Lines.Add('Start Time: ' + IntToStr(x.StartTime));
      Lines.Add('Until Time: ' + IntToStr(x.UntilTime));

      {According to the Win32 help files we can not test for all of these printer
      states under Windows NT. I have found that a lot of them (those that I've commented
      out) has no constants declared for them. The constants which are declared
      can be found in the Winspool.Pas file.

      Unfortunately it seems as if a lot of time the printer status are not
      picked up correctly}
      If x.Status = PRINTER_STATUS_BUSY then
            Lines.Add('Status: The printer is busy')
      else If x.Status = PRINTER_STATUS_DOOR_OPEN then
            Lines.Add('Status: The printer door is open')
//      else If x.Status = PRINTER_STATUS_PRINTER_STATUS_ERROR then
//            Lines.Add('Status: The printer is in an error state')
//      else If x.Status = PRINTER_STATUS_PRINTER_STATUS_INITIALIZING then
//            Lines.Add('Status: The printer is initializing')
//      else If x.Status = PRINTER_STATUS_PRINTER_STATUS_IO_ACTIVE then
//            Lines.Add('Status: The printer is in an active input/output state')
      else If x.Status = PRINTER_STATUS_MANUAL_FEED then
            Lines.Add('Status: The printer is in a manual feed state')
      else If x.Status = PRINTER_STATUS_NOT_AVAILABLE then
            Lines.Add('Status: The printer is out of toner')
      else If x.Status = PRINTER_STATUS_NOT_AVAILABLE then
            Lines.Add('Status: The printer is not available for printing')
      else If x.Status = PRINTER_STATUS_OFFLINE then
            Lines.Add('Status: The printer is offline')
      else If x.Status = PRINTER_STATUS_OUT_OF_MEMORY then
            Lines.Add('Status: The printer has run out of memory')
      else If x.Status = PRINTER_STATUS_OUTPUT_BIN_FULL then
            Lines.Add('Status: The printer''s output bin is full')
      else If x.Status = PRINTER_STATUS_PAGE_PUNT then
            Lines.Add('Status: The printer cannot print the current page')
      else If x.Status = PRINTER_STATUS_PAPER_JAM then
            Lines.Add('Status: Paper is jammed in the printer')
      else If x.Status = PRINTER_STATUS_PAPER_OUT then
            Lines.Add('Status: The printer is out of paper')
      else If x.Status = PRINTER_STATUS_PAPER_PROBLEM then
            Lines.Add('Status: The printer has a paper problem')
      else If x.Status = PRINTER_STATUS_PENDING_DELETION then
            Lines.Add('Status: Pending Deletion')
      else If x.Status = PRINTER_STATUS_PAUSED then
            Lines.Add('Status: The printer is paused')
      else If x.Status = PRINTER_STATUS_PENDING_DELETION then
            Lines.Add('Status: The printer is deleting a print job')
      else If x.Status = PRINTER_STATUS_PRINTING then
            Lines.Add('Status: The printer is printing')
      else If x.Status = PRINTER_STATUS_PROCESSING then
            Lines.Add('Status: The printer is processing a print job')
      else If x.Status = PRINTER_STATUS_TONER_LOW then
            Lines.Add('Status: The printer is low on toner')
//      else If x.Status = PRINTER_STATUS_UNAVAILABLE then
//            Lines.Add('Status: The printer is not available for printing')
//      else If x.Status =  then PRINTER_STATUS_USER_INTERVENTION
//            Lines.Add('Status: The user needs to do something to the printer')
      else If x.Status = PRINTER_STATUS_WAITING then
            Lines.Add('Status: The printer is waiting')
      else If x.Status = PRINTER_STATUS_WARMING_UP then
            Lines.Add('Status: The printer is warming up')
      else
            Lines.Add('Status: ' + IntToStr(x.Status));

      Lines.Add('Jobs: ' + IntToStr(x.Jobs));

      Lines.Add('Average PPM: ' + IntToStr(x.AveragePPM));
      Lines.Add(' ');
      Lines.Add('JOBS');

      PrinterEx1.UpdateJobs(I);
      try
        For J := 0 to PrinterEx1.JobsCount - 1 do begin
          Memo1.Lines.Add('JobID: ' + IntToStr(PrinterEx1.Job[J].JobId));
          Memo1.Lines.Add('Printer Name: ' + PrinterEx1.Job[J].PrinterName);
          Memo1.Lines.Add('Machine Name: ' + PrinterEx1.Job[J].MachineName);
          Memo1.Lines.Add('User Name: ' + PrinterEx1.Job[J].UserName);
          Memo1.Lines.Add('Document: ' + PrinterEx1.Job[J].Document);
          Memo1.Lines.Add('Notify Name: ' + PrinterEx1.Job[J].NotifyName);
          Memo1.Lines.Add('Data Type: ' + PrinterEx1.Job[J].DataType);
          Memo1.Lines.Add('Print processor: ' + PrinterEx1.Job[J].PrintProcessor);
          Memo1.Lines.Add('dStatus: ' + PrinterEx1.Job[J].dStatus);

          If PrinterEx1.Job[J].dwStatus = JOB_STATUS_PAUSED then
                Memo1.Lines.Add('dwStatus: Paused')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_ERROR then
                Memo1.Lines.Add('dwStatus: Error')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_DELETING then
                Memo1.Lines.Add('dwStatus: Deleting')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_SPOOLING then
                Memo1.Lines.Add('dwStatus: Spooling')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_PRINTING then
                Memo1.Lines.Add('dwStatus: Printing')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_OFFLINE then
                Memo1.Lines.Add('dwStatus: Off Line')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_PAPEROUT then
                Memo1.Lines.Add('dwStatus: Peper out')
          else if PrinterEx1.Job[J].dwStatus = JOB_STATUS_PRINTED then
                Memo1.Lines.Add('dwStatus: Printed');
//          else
                Memo1.Lines.Add('dwStatus: ' + IntToStr(PrinterEx1.Job[J].dwStatus));

          Memo1.Lines.Add('Priority: ' + IntToStr(PrinterEx1.Job[J].Priority));
          Memo1.Lines.Add('Position: ' + IntToStr(PrinterEx1.Job[J].Position));
          Memo1.Lines.Add('Start Time: ' + IntToStr(PrinterEx1.Job[J].StartTime));
          Memo1.Lines.Add('Until Time: ' + IntToStr(PrinterEx1.Job[J].Untiltime));
          Memo1.Lines.Add('Total Pages: ' + IntToStr(PrinterEx1.Job[J].TotalPages));
          Memo1.Lines.Add('Size: ' + IntToStr(PrinterEx1.Job[J].Size));
          Memo1.Lines.Add('Time: ' + IntToStr(PrinterEx1.Job[J].Time));
          Memo1.Lines.Add('Pages Printed: ' + IntToStr(PrinterEx1.Job[J].PagesPrinted));
          Memo1.Lines.Add(' ');
        end;
      except
      end;
    end;
  end;
end;
end.
<----------------------------------------------------------------------------------------->
PrinterEx component Demo - Unti1.Pas file end

PrinterEx component Demo - Unti1.dfm file start
<----------------------------------------------------------------------------------------->
object Form1: TForm1
  Left = 270
  Top = 103
  Width = 557
  Height = 456
  Caption = 'PrinterEx Demo'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Panel2: TPanel
    Left = 0
    Top = 0
    Width = 549
    Height = 49
    Align = alTop
    Caption = 'By: Gerhard van Rensburg - gerhardvr@email.com'
    TabOrder = 0
  end
  object Panel3: TPanel
    Left = 0
    Top = 49
    Width = 549
    Height = 380
    Align = alClient
    Caption = 'Panel3'
    TabOrder = 1
    object Memo1: TMemo
      Left = 1
      Top = 1
      Width = 547
      Height = 378
      Align = alClient
      ScrollBars = ssVertical
      TabOrder = 0
    end
  end
  object Button1: TButton
    Left = 16
    Top = 16
    Width = 75
    Height = 25
    Caption = '&Go'
    TabOrder = 2
    OnClick = Button1Click
  end
  object PrinterEx1: TPrinterEx
    Left = 104
    Top = 16
  end
end
<----------------------------------------------------------------------------------------->
PrinterEx component Demo - Unti1.dfm file end

0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 8

Expert Comment

by:ZifNab
ID: 1341852
.... Tazi, what if printer becomes off-line when you already sended it to this printer, because then it was On-line...
0
 

Author Comment

by:Tazi
ID: 1341853
Zifnab...Well, if the printer goes offline after i have send the document thats another problem altogether..I am currently only interested in checking the status of the printer before i send a document to it  This is the most important problem to solve at this stage - I get telephone calls from clients at 11:30pm and 12:00am and all i have to do is take them through the steps of putting the printer back online and everything seems to work 100%.  If I can get this code to detect printer online and offline at least I won't have to receive telephone calls in the middle of the night . . .hey
Regards, Tazi
0
 

Author Comment

by:Tazi
ID: 1341854
Gerhard, Thanks ...I have saved this and I am busy evaluating it.  I will keep u informed  Thanks a whole lot.

Regards
Tazi
0
 

Author Comment

by:Tazi
ID: 1341855
Gerhard....

Thanks for the info u posted above..But I have been using the very same component and have been suffering with it for the past 3 days.  It doesn't bring back the correct status all the time.  Would u perhaps know the difference between

      - Work Offline
      - Use Printer Offline

Both of these obtions are available if u are using a network printer.  If Use Offline is selected, the PrinterEx component (I have made some modification - not the same as u have) brings back
1048576 as the decimal number which when converted to hexadecimal becomes 100000.  So physically if u check the status of the printer in the Winspool.pas file, it brings back  [ Printer_Status_User_Intervention ] which is correct, the pause as u mentioned works 100%.  However, if Work offline is selected, the document spools in the spooler forver.  The status this component brings back is [ Job_Status_Printing ] and [ Job_Status_Spooling ] this never changes and remains in this state until u delete the job.  If u print a test page to the printer when it is in this state, the windows popup (" Windows cannot print to the specified device LPT1..........It will automatically retry after 5 seconds   [RETRY] AND [CANCEL")

I need some way to control the entire print spooler with my own messages, i don't want to be prompted with this windows popup.  There must be a value which changes in Windows registry specifying if the printer is set to work offline or not...If this is the case, then i need to read the registry in some way.  

This is a tough one......I will send u the code tomorrow.  unfortunately I don't have my modem connected to my laptop....

Anyway if u have any answers please keep me posted

Many thanks
Tazi
0
 
LVL 1

Expert Comment

by:Gerhard100198
ID: 1341856
Tazi,

You've run into exactly the same problems I did.

You've got to remember exactly what "Work offline" is intended for. It allows Windows to print to the spool file and to be "fooled" into believing that everything is OK with the printer.
In practice this could mean that you install a printer driver on your PC without even owning a printer and you could then print to it! Granted, the data would just end up in the spool file but nothing would complain about the fact that there is no printer connected to the PC.

As for where this setting is stored, I haven't got the foggiest.

I still believe that there must be a way to query the printer direct. I don't want to ask Windows what the printer's status is, I want to ask the printer (like I could do in DOS).
0
 

Author Comment

by:Tazi
ID: 1341857
Gerhard...It seems as if we are both suffering with the damn same thing..

Well, I have gotton somewhere today.  "Work offline" is very different from "Use Printer Offline" .  U can retrieve the status of the printer at any time, when u send a document to the printer and "Work Offline" is selected, u receive the status [Job_Status_Offline].  The work offline works with the JOB that is being sent to the printer, not the Printer_Status.  I have created a fancy little demo.  Please give me your email address and I will mail it to u. I suffered a whole lot, but i seem to be getting there slowly.  However, know i get this silly windows popup that comes up all the time, saying retry or cancel - [Windows cannot print to the LPT1 - the printer must be offline, [retry] or [cancel].  i need to get rid of this popup, so, if the status retrieved is JOB_STATUS_OFFLINE  or JOB_STATUS_USER_INTERVENTION then I need to deleted the print job.  Have any ideas......This is one problem..I use BeginDoc and Enddoc for printing.  I cannot use the abort method to end the job because abort can only be called before enddoc.  If i check the status before enddoc is called it is JOB_STATUS_SPOOLING so i have to check the status after the enddoc is called.  How would i then cancel the job....

My email address is <mumtaz@mweb.co.za> - - - I will send this demo to u

Still suffereing
...Thanks for your help.

Regards....Tazi


0
 
LVL 1

Expert Comment

by:Gerhard100198
ID: 1341858
Tazi,

My email: gerhardvr@email.com or jvrensgg@telkom.co.za

Some of the printer drivers actually allow you to switch off the message you're complaining about. I'm not too sure whether it's a driver setting or a Windows setting.

Not too sure about deleteing the job after it's been printed. There must however be a WinAPI call to handle it. I'll see what I can find (if I get the time today ;) )

Good luck

Gerhard
0
 

Author Comment

by:Tazi
ID: 1341859
Gerhard, i have tons of questions for u...

I got the job deleted using the following function SetJob( ).  I still get the popup which eventually disappears after the job is deleted.  I don't want that popup to appear.  Please let me know about the various drivers that u are talking about.

I will email the code to u (The demo) that i have created..I can cancel a local job, a network job however retrieves a printer status of zero ( 0 ).  Why is the shared printer over the network have a "Work offline" and "Use Printer offline" option.  The status cannot be detected if the printer is a network printer.  I am almost there, with a little more effort i will get it right.  

Thanks for your effort

Regards
Tazi


0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now