Click to See Complete Forum and Search --> : How to list printer jobs


Clearcode
October 1st, 2001, 05:56 AM
I have been working on code to list the printer jobs for any given printer. This is what I have so far...
(assumes a form with a listview control and a combo box control on it)


'Declarations...
option Explicit

'\\ API Declarations
private Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" _
(byval hPrinter as Long, _
byval FirstJob as Long, _
byval NoJobs as Long, _
byval Level as Long, _
pJob as Long, _
byval cdBuf as Long, _
pcbNeeded as Long, _
pcReturned as Long) as Long


private Type PRINTER_DEFAULTS
pDatatype as string
pDevMode as Long
DesiredAccess as Long
End Type


private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(byval pPrinterName as string, _
phPrinter as Long, _
pDefault as PRINTER_DEFAULTS) as Long

private Declare Function ClosePrinter Lib "winspool.drv" (byval hPrinter as Long) as Long

'\\ Declarations for StringFromPointer
private Declare Function IsBadStringPtrByLong Lib "kernel32" Alias "IsBadStringPtrA" (byval lpsz as Long, byval ucchMax as Long) as Long

private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination as Any, _
Source as Any, _
byval Length as Long)




First we need to get a list of all the printers on this system in a combo box (and init the listview as well) in the Form_Load:


private Sub Form_Load()

'\\ List all the printers into the combo box...
Dim prtThis as Printer

cmbPrinters.Clear
for Each prtThis In Printers
cmbPrinters.AddItem prtThis.DeviceName
next prtThis
'\\ set printer list to current printer
cmbPrinters.Text = Printer.DeviceName


'\\ set the columns of the listview
With lvwPrintJobs.ColumnHeaders
.Clear
.Add , "JOB_ID", "Job Id", 1440
.Add , "USER", "User", 1440
.Add , "DOCUMENT", "Document", 1440
.Add , "DATATYPE", "Data Type", 1440
End With

End Sub




Then whenever the listbox is clicked we need to list the jobs on that printer.


private Sub cmbPrinters_Click()

Call RefreshJobList(cmbPrinters.Text)

End Sub

'\\ --[RefreshJobList]----------------------------------------------
'\\ Fills the listview control with information on the currently
'\\ active print jobs
'\\ ----------------------------------------------------------------
public Sub RefreshJobList(byval PrinterName as string)

Dim mPrintHandle as Long, lRet as Long
Dim pDEf as PRINTER_DEFAULTS

Dim pcBytesRequired as Long, pcRecordsReturned as Long
Dim pBuff() as Long
Dim nJob as Long, pJobOffset as Long

'\\ Obtain a handle to the named printer
lRet = OpenPrinter(PrinterName, mPrintHandle, pDEf)
If Err.LastDllError = 0 then
'\\ Clear any existing listed jobs...
lvwPrintJobs.ListItems.Clear
If mPrintHandle <> 0 then
'\\ get size of buffer required to hold printer jobs info
ReDim Preserve pBuff(0) as Long
lRet = EnumJobs(mPrintHandle, 0, 255, 1, pBuff(0), UBound(pBuff) * 4, pcBytesRequired, pcRecordsReturned)
If pcBytesRequired > 0 then
ReDim Preserve pBuff(0 to (pcBytesRequired / 4) + 3) as Long
lRet = EnumJobs(mPrintHandle, 0, 255, 1, pBuff(0), UBound(pBuff) * 4, pcBytesRequired, pcRecordsReturned)
End If
If pcRecordsReturned > 0 then
'\\ for each job, decode its records....
for nJob = 0 to (pcRecordsReturned - 1)
'\\ Each record is 16 longs...
pJobOffset = nJob * 16
'\\ add the current job to the list
lvwPrintJobs.ListItems.Add , "JOB" & nJob, pBuff(pJobOffset)
'\\ Username is in Offset+3
lvwPrintJobs.ListItems.Item(lvwPrintJobs.ListItems.Count).SubItems(1) = StringFromPointer(pBuff(pJobOffset + 3), 1024)
'\\ Document is in Offset+4
lvwPrintJobs.ListItems.Item(lvwPrintJobs.ListItems.Count).SubItems(2) = StringFromPointer(pBuff(pJobOffset + 4), 1024)
'\\ DataType is in Offset+5
lvwPrintJobs.ListItems.Item(lvwPrintJobs.ListItems.Count).SubItems(3) = StringFromPointer(pBuff(pJobOffset + 5), 1024)
next nJob
End If

'\\ Release the named printer's handle
lRet = ClosePrinter(mPrintHandle)
End If
End If

End Sub




Note that because we have passed a buffer of Long values, our string values (user name, document name etc) are returned as pointers so we need to convert them to strings to use them..


private Function StringFromPointer(lpString as Long, lMaxlength as Long) as string

Dim sRet as string
Dim lRet as Long

If lpString = 0 then
StringFromPointer = ""
Exit Function
End If

If Not IsBadStringPtrByLong(lpString, lMaxlength) then
'\\ set aside space to copy string to
sRet = string$(lMaxlength, 0)
CopyMemory byval sRet, byval lpString, byval len(sRet)
If InStr(sRet, Chr$(0)) > 0 then
sRet = Left$(sRet, InStr(sRet, Chr$(0)) - 1)
End If
End If

StringFromPointer = sRet

End Function




HTH,
Duncan

(When complete, this functionality will be included in the EventVB Win32API wrapper project to allow syntax like:


for Each ApiPrintJob In Printer.PrintJobs
Debug.print ApiPrintJob.Username
next ApiPrintJob



)

-------------------------------------------------
Ex. Datis: Duncan Jones
Merrion Computing Ltd
http://www.merrioncomputing.com
Check out the new downloads - ImageMap.ocx is the VB control that emulates an HTML image map, EventVB.OCX for adding new events to your VB form and adding System Tray support simply, MCL Hotkey for implemenmting system-wide hotkeys in your application...all with source code included.

Cimperiali
October 1st, 2001, 06:04 AM
You know.
;-)


Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, TCartwright, Bruno Paris, Dr_Micahel
and all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.

The Rater