Tazi
asked on
Detecting Printer Status ... Help?
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
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:BYT E); ;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(LP T1))
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;
========================== ========== =
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:BYT
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(LP
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;
==========================
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?
Still, why do you need it?
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
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
ASKER
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....
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....
ASKER
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....
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....
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
.... Tazi, what if printer becomes off-line when you already sended it to this printer, because then it was On-line...
ASKER
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
Regards, Tazi
ASKER
Gerhard, Thanks ...I have saved this and I am busy evaluating it. I will keep u informed Thanks a whole lot.
Regards
Tazi
Regards
Tazi
ASKER
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_Interv ention ] 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
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_Interv
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
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).
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).
ASKER
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_INTERVENTI ON 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
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_INTERVENTI
My email address is <mumtaz@mweb.co.za> - - - I will send this demo to u
Still suffereing
...Thanks for your help.
Regards....Tazi
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
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
ASKER
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
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
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.