Farabi's code is perfect for determining if a printer is online, but I need to bypass the printer dialog box.
Thanks.
call fPrintDC
invoke ExitProcess,0
fPrintDC proc hWnd:dword,hDC:dword
LOCAL p: PRINTDLG
LOCAL _di:DOCINFO
LOCAL p2:PRINTDLG
LOCAL prx,pry:dword
LOCAL b:BITMAP
LOCAL buff[256]:dword
LOCAL p_dim:POINT
LOCAL p_dim2:POINT
LOCAL fnm:DWORD
.if hDC==0
ret
.endif
invoke memfill, addr _di,sizeof DOCINFO,0
mov _di.cbSize,sizeof DOCINFO
lea eax,fnm
mov _di.lpszDocName,eax
mov _di.lpszOutput,0
mov _di.lpszDatatype,0
mov _di.fwType,0
invoke memfill, addr p2,sizeof PRINTDLG-4,0
mov p2.lStructSize,sizeof PRINTDLG
mov p2.Flags,PD_RETURNDC
invoke PrintDlg,addr p2
.if eax!=0
.if p2.hDC==0
invoke MessageBox,0,CADD("Printer DC is wrong"),0,0
.endif
invoke GetDeviceCaps,p2.hDC,VERTRES
mov p_dim.x,eax
invoke GetDeviceCaps,p2.hDC,HORZRES
mov p_dim.y,eax
invoke GetDeviceCaps,hDC,VERTRES
mov p_dim2.x,eax
invoke GetDeviceCaps,hDC,HORZRES
mov p_dim2.y,eax
invoke StartDoc,p2.hDC,addr _di
.if eax==SP_ERROR
invoke MessageBox,0,CADD("Cannot start, document"),0,0
.endif
invoke StartPage,p2.hDC
.if eax<=0
invoke MessageBox,0,CADD("Cannot start printer"),0,0
.endif
invoke StretchBlt,p2.hDC,0,0,p_dim.x,p_dim.y,hDC,0,0,p_dim2.x,p_dim2.y,SRCCOPY
;invoke BitBlt,p2.hDC,0,0,p_dim.x,p_dim.y,hDC,0,0,SRCCOPY
invoke EndPage,p2.hDC
invoke EndDoc,p2.hDC
invoke DeleteDC,p2.hDC
.endif
ret
fPrintDC endp
You can use the "default" printer:
pPrintInfo db 80 DUP (?)
;Get default printer info
invoke GetProfileString, CTEXT("windows"), CTEXT("Device"), CTEXT(" "), \
addr pPrintInfo, sizeof pPrintInfo
;Default printer exists before first comma
lea esi, pPrintInfo ;first char of printer name
dec esi
check_com:
inc esi
cmp byte ptr [esi], ','
jnz check_com
mov byte ptr [esi], 0 ;replace comma with 0 ending printer name string
inc esi
mov pPrintDriver, esi ;beginning of printer driver text
dec esi
get_driver:
inc esi
cmp byte ptr [esi], ','
jnz get_driver
mov byte ptr [esi], 0 ;replace comma with 0 ending printer driver string
get_port:
inc esi
mov pPrintPort, esi ;beginning of printer port text
cmp byte ptr [esi], ','
jnz get_port
mov byte ptr [esi], 0 ;replace comma with 0 ending printer port string
push NULL
push offset hPrinter
push offset pPrintInfo
call pOpenPrinterA ;Open printer, it looks like this because I had to find the address
; of OpenPrinter for different OS versions.
hth,
farrier
Or under Windows 2000 and later you can use the GetDefaultPrinter function.
Code has many errors.
If Lexmark can determine if printer is ready, asm coders should be able to figure this out. :t
sure - Lexmark undoubtedly has a kernel mode driver and can read the I/O port directly
there is probably some way to do it with IOCTL, but i'll be danged if i know what it is - lol
Magnum,
You're welcomed!
Exactly what are you asking help with? You ask about online vs. offline, and bypassing printer dialog. You have the tools to do both! What code had errors?
My suggestion: Use more words to define your problems! Pretend we don't know what you are trying to accomplish! Oh, and fix you signature line, it's annoying to a fan of Star Wars!
farrier
I would think that you could determine the online state from the printer status, but apparently not. I tested this with PRINTER_INFO_2 and PRINTER_INFO_6.
;==============================================================================
include \masm32\include\masm32rt.inc
include \masm32\include\winspool.inc
includelib \masm32\lib\winspool.lib
;==============================================================================
PRINTER_INFO_6 STRUCT
dwStatus DWORD ?
PRINTER_INFO_6 ENDS
;==============================================================================
.data
hPrinter dd 0
cbNeeded dd 0
cch dd 100
buffer db 100 dup(0)
.code
;==============================================================================
start:
;==============================================================================
invoke GetDefaultPrinter, ADDR buffer, ADDR cch
printf("%d\t%s\n", eax, ADDR buffer)
invoke OpenPrinter, ADDR buffer, ADDR hPrinter, NULL
printf("%d\t%Xh\n", eax, hPrinter)
invoke GetPrinter, hPrinter, 6, 0, 0, ADDR cbNeeded
printf("%d\t%d\n", eax, cbNeeded)
mov ebx, alloc(cbNeeded)
invoke GetPrinter, hPrinter, 6, ebx, cbNeeded, ADDR cbNeeded
printf("%d\t%d\n\n", eax, [ebx].PRINTER_INFO_6.dwStatus)
inkey
exit
;==============================================================================
end start
I can't help but wonder what the rationale for this is.
GetProfileString, CTEXT("windows"), CTEXT("device")
Looks ancient when considering that you may have dozens of devices nowadays. And it is indeed ancient:
QuoteWindows NT maps most .ini file references to the registry. As a result, GetProfileString and WriteProfileString still function as if they were running under 16-bit Windows (Microsoft Windows and Windows for Workgroups). (http://support.microsoft.com/kb/246772)
There is also some official M$ sample code, but: "The code appears to not work in some circumstances"
Note the cautious "appears to" :biggrin:
the GetPrinterStatus API seems to apply to the spooler - not the actual printer, port, or its' device driver
so, my understanding is that you are getting the status of the spooler, which is almost always ready - lol
it seems you should be able to get the printer status by communicating with the device driver
that would go something like opening a file handle and using the DeviceIoControl function
and - the drivers may be different from one to another, but some of the interface should be standardized
Hi,
Michael, here are the results of your program on my machine.
First with printer off, second with it on.
1 HP Color LaserJet 2550n PS
1 1353FCh
0 4
1 0
Press any key to continue ...
G:\WORK>test42
1 HP Color LaserJet 2550n PS
1 1353FCh
0 4
1 0
Press any key to continue ...
Regards,
Steve
Farrier,
CTEXT did not work, but it was fixed.
C:\masm32\SOURCE\print1.asm(42) : error A2006: undefined symbol : pPrintDriver
C:\masm32\SOURCE\print1.asm(51) : error A2006: undefined symbol : pPrintPort
C:\masm32\SOURCE\print1.asm(57) : error A2006: undefined symbol : hPrinter
C:\masm32\SOURCE\print1.asm(59) : error A2006: undefined symbol : pOpenPrinterA
For PRINTER_INFO_2 and PRINTER_INFO_6 winspool.h defines a range of values for the status member that appear to be intended to report the printer status:
#define PRINTER_STATUS_PAUSED 0x00000001
#define PRINTER_STATUS_ERROR 0x00000002
#define PRINTER_STATUS_PENDING_DELETION 0x00000004
#define PRINTER_STATUS_PAPER_JAM 0x00000008
#define PRINTER_STATUS_PAPER_OUT 0x00000010
#define PRINTER_STATUS_MANUAL_FEED 0x00000020
#define PRINTER_STATUS_PAPER_PROBLEM 0x00000040
#define PRINTER_STATUS_OFFLINE 0x00000080
#define PRINTER_STATUS_IO_ACTIVE 0x00000100
#define PRINTER_STATUS_BUSY 0x00000200
#define PRINTER_STATUS_PRINTING 0x00000400
#define PRINTER_STATUS_OUTPUT_BIN_FULL 0x00000800
#define PRINTER_STATUS_NOT_AVAILABLE 0x00001000
#define PRINTER_STATUS_WAITING 0x00002000
#define PRINTER_STATUS_PROCESSING 0x00004000
#define PRINTER_STATUS_INITIALIZING 0x00008000
#define PRINTER_STATUS_WARMING_UP 0x00010000
#define PRINTER_STATUS_TONER_LOW 0x00020000
#define PRINTER_STATUS_NO_TONER 0x00040000
#define PRINTER_STATUS_PAGE_PUNT 0x00080000
#define PRINTER_STATUS_USER_INTERVENTION 0x00100000
#define PRINTER_STATUS_OUT_OF_MEMORY 0x00200000
#define PRINTER_STATUS_DOOR_OPEN 0x00400000
#define PRINTER_STATUS_SERVER_UNKNOWN 0x00800000
#define PRINTER_STATUS_POWER_SAVE 0x01000000
But in my tests, with a USB-connected LaserJet 1012, the status member value was apparently always zero, which as you can see is not defined. Thinking that the problem may be the USB connection, I installed a PP-connected LaserJet 4050, and while I was able to print a test page with it and my app was able to recognize it, the status member value was, again, apparently always zero. Initializing a PRINTER_DEFAULTS structure for PRINTER_ALL_ACCESS and passing it to the OpenPrinter function did not correct the problem, nor did running the app as administrator.
Experimenting further, by attempting to print something on the printer, and under certain conditions, I can get a non-zero status value, PRINTER_STATUS_PAUSED for example. This whole thing appears to be not very well worked out, and I have now wasted more than enough time on it.
;==============================================================================
include \masm32\include\masm32rt.inc
include \masm32\include\winspool.inc
includelib \masm32\lib\winspool.lib
;==============================================================================
PRINTER_INFO_6 STRUCT
dwStatus DWORD ?
PRINTER_INFO_6 ENDS
;==============================================================================
.data
hPrinter dd 0
cbNeeded dd 0
cch dd 100
pd PRINTER_DEFAULTS <0,0,PRINTER_ALL_ACCESS>
buffer db 100 dup(0)
.code
;==============================================================================
start:
;==============================================================================
invoke GetDefaultPrinter, ADDR buffer, ADDR cch
printf("%d\t%s\n", eax, ADDR buffer)
invoke OpenPrinter, ADDR buffer, ADDR hPrinter, ADDR pd
printf("%d\t%Xh\n", eax, hPrinter)
invoke GetPrinter, hPrinter, 2, 0, 0, ADDR cbNeeded
printf("%d\t%d\n", eax, cbNeeded)
mov ebx, alloc(cbNeeded)
invoke GetPrinter, hPrinter, 2, ebx, cbNeeded, ADDR cbNeeded
printf("%d\t%d\n", eax, [ebx].PRINTER_INFO_2.Status)
mov eax, [ebx].PRINTER_INFO_2.pPrinterName
printf("%s\n\n", eax)
inkey
exit
;==============================================================================
end start
http://support.microsoft.com/kb/160129/EN-US
I really appreciate everyone's help with this.
Andy
I haven't given up yet.
This doesn't work right.
; Obtain printer attributes and check against PRINTER_ATTRIBUTE_WORK_OFFLINE flag.
include \masm32\include\masm32rt.inc
include \masm32\include\winspool.inc
includelib \masm32\lib\winspool.lib
PRINTER_INFO_5W STRUCT
pPrinterName DWORD ?
pPortName DWORD ?
Attributes DWORD ?
DeviceNotSelectedTimeout DWORD ?
TransmissionRetryTimeout DWORD ?
PRINTER_INFO_5W ENDS
;==============================================================================
.data
hPrinter dd 0
cbNeeded dd 0
cch dd 100
pd PRINTER_DEFAULTS <0,0,PRINTER_ALL_ACCESS>
buffer db 100 dup(0)
.code
;==============================================================================
start:
;==============================================================================
; PRINTER_STATUS_OFFLINE
invoke GetDefaultPrinter, ADDR buffer, ADDR cch
printf("%d\t%s\n", eax, ADDR buffer)
invoke OpenPrinter, ADDR buffer, ADDR hPrinter, ADDR pd
printf("%d\t%Xh\n", eax, hPrinter)
invoke GetPrinter, hPrinter, 6, 0, 0, ADDR cbNeeded
printf("%d\t%d\n", eax, cbNeeded)
mov ebx, alloc(cbNeeded)
;
; Attributes
;
; Specifies the printer attributes. This member can be one of the following values:
;
; PRINTER_ATTRIBUTE_QUEUED
; PRINTER_ATTRIBUTE_DIRECT
; PRINTER_ATTRIBUTE_DEFAULT
; PRINTER_ATTRIBUTE_SHARED
; PRINTER_ATTRIBUTE_WORK_OFFLINE
invoke GetPrinter, hPrinter, 6, ebx, cbNeeded, ADDR cbNeeded
printf("%d\t%d\n", eax, [ebx].PRINTER_INFO_5W.Attributes)
int 3
inkey
exit
;==============================================================================
end start
Visual Basic Script from Todd Vargo
Now I am trying to figure out where to insert a program I want to start if the printer is offline.
PrinterName = "Lexmark 2600 Series"
Set sa = CreateObject("Shell.Application")
Set printers = sa.NameSpace(4).Items()
VerbName = "&Use Printer Online"
For each printer in printers
If printer.Name = PrinterName Then
For Each verb in printer.Verbs
If verb.Name = VerbName Then
WScript.Echo PrinterName & " is offline"
End If
Next
End If
Next