News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Determine printer status

Started by Magnum, March 27, 2013, 09:24:28 AM

Previous topic - Next topic

Magnum

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

Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

farrier

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

MichaelW

Or under Windows 2000 and later you can use the GetDefaultPrinter function.
Well Microsoft, here's another nice mess you've gotten us into.

Magnum

Code has many errors.

If Lexmark can determine if printer is ready, asm coders should be able to figure this out.  :t
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

dedndave

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

farrier

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

MichaelW

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.
Well Microsoft, here's another nice mess you've gotten us into.

jj2007

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).

There is also some official M$ sample code, but: "The code appears to not work in some circumstances"
Note the cautious "appears to" :biggrin:

dedndave

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

FORTRANS

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

Magnum

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
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

MichaelW

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

Well Microsoft, here's another nice mess you've gotten us into.

Magnum

I really appreciate everyone's help with this.

Andy
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

Magnum

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

Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

Magnum

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
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org