| Win32 API and Printers: Print Directly to a Printer |
|
|
| Contributed by Rick Kelly | |
| 17 August 2002 | |
|
Learn how to print directly to the printer without going through the usual print dialogs.Win32 API and Printers Print Directly to a Printer © 2002 Rick Kelly www.crooit.com Preface Libraries and forms (Paradox 9) presented are available as a download here. Paradox 8 is not supported although Paradox 7-32 surprisingly works. After downloading into the folder of your choice, make that folder :WORK: and run the included form for a demonstration. You'll need to run the form before opening it in design mode as it references table :PRIV:__PJobs that is created in the form's INIT event. (If running Paradox 10, or if the table doesn't get created properly, you should first run the BldSpool.ssl script prior to running the form.) Introduction Previous articles in this series:
There are times when using Paradox? reports just doesn't get the job done or you've got a PostScript or PCL file generated on another system that you wish to print. In both cases, sending raw print data directly to the printer and bypassing the Windows print driver gives you precise control of your printed output. To send data directly to the printer under Win32, the following steps need to be followed.
Referenced Win32 APIs Other referenced Win32 API's have been covered in earlier articles. Newly introduced methods are: StartDocPrinter( hPrn cLong, cLevel cLong, pDocInfo cLong) cLong [stdcall "StartDocPrinterA"] StartPagePrinter(hPrn cLong) cLong [stdcall] WritePrinter( hPrn cLong, pBuf cPtr, size cLong, pcWritten cPtr) clong [stdcall] EndPagePrinter(hPrn cLong) cLong [stdcall] EndDocPrinter(hPrn cLong) cLong [stdcall]hPrn - Handle to the printer cLevel = Level or type of printer information structure to return - always 1 for our use pDocInfo - pointer to document information structure pBuf - Printer data to send size - Size of pBuf pcWritten - Bytes written Direct access to Windows printers As there are several pieces of information that must be shared between our methods, we will create the following Record Type to keep everything in one place. Type
W32DirectPrintInfo =
Record
Printer String
DocumentName String
DocumentContent String
DocumentSpacing SmallInt
DocumentSpacingAfter Logical
DocumentFormFeed Logical
DocumentFormFeedAfter Logical
PrinterHandle LongInt ;Do not modify
DocumentStructure LongInt ;Do not modify
BytesWritten LongInt ;Do not modify
endRecord
endType
Where:Printer = Name of printer to write to. DocumentName = Name of our document or print job. DocumentContent = Raw printer data to send. DocumentSpacing = Option line spacing. If > 0, the number specified indicates how many carriage return/line feeds to insert in the data stream. DocumentSpacingAfter = True - After DocumentContent has been sent, False - Before. DocumentFormFeed = True if a form feed is to be inserted into data stream DocumentFormFeedAfter = True - After DocumentContent has been sent, False - Before PrintHandle = Windows printer handle DocumentStructure = Windows Document Information Level 1 Structure pointer BytesWritten = Total bytes sent to the spooler Constants referenced by our methods: Const ; ; Standard ASCII printer control ; cnLineFeed = 10 cnFormFeed = 12 cnCarriageReturn = 13 endConstWe'll use three methods to encapsulate all the Win32 API calls needed. method OpenPrinterDirect(var dpi W32DirectPrintInfo) Logical
var
loReturn Logical
liAny LongInt
stAny String
liSize LongInt
liReturn LongInt
apAny Application
endVar
loReturn = False
;
; Get a handle to the printer and initialize our structure
;
dpi.PrinterHandle = 0
dpi.BytesWritten = 0
dpi.DocumentSpacing = 0
dpi.DocumentSpacingAfter = True
dpi.DocumentFormFeed = False
dpi.DocumentFormFeedAfter = True
liReturn = OpenPrinter(dpi.Printer,dpi.PrinterHandle,0)
;
; Check if a valid printer name was found
;
switch
case liReturn <> 1 :
otherwise :
;
; Ensure we have a document name
;
switch
case dpi.DocumentName.isAssigned() = False :
dpi.DocumentName = apAny.getTitle()
switch
case dpi.DocumentName.isBlank() :
dpi.DocumentName = "Corel Paradox"
endSwitch
endSwitch
;
; Allocate memory for Document Info 1 structure
;
; Document Name Pointer LongInt
; Output File Name Pointer LongInt - zero
; Data Type Pointer LongInt
; dpi.DocumentName String + x'00'
; Data Type String - "RAW" + x'00'
;
liSize = dpi.DocumentName.size()
liAny = liSize + 17
dpi.DocumentStructure = GlobalAlloc(fromHex("0x40"),liAny)
liAny = dpi.DocumentStructure + 12
MoveToMemory(dpi.DocumentStructure,liAny,4)
MoveToMemory(liAny,dpi.DocumentName,liSize + 1)
liAny = dpi.DocumentStructure + 13 + liSize
MoveToMemory(dpi.DocumentStructure + 8,liAny,4)
stAny = "RAW"
MoveToMemory(liAny,stAny,4)
liReturn = StartDocPrinter(
dpi.PrinterHandle,
1,
dpi.DocumentStructure)
liReturn = StartPagePrinter(dpi.PrinterHandle)
loReturn = True
endSwitch
return loReturn
endMethod
method WritePrinterDirect(var dpi W32DirectPrintInfo) Logical
var
loReturn Logical
liAny LongInt
liSize LongInt
liReturn LongInt
stControl String
endVar
loReturn = False
stControl = blank()
;
; Check for any spacing
;
switch
case dpi.DocumentSpacing > 0 :
for liAny from 1 to dpi.DocumentSpacing
stControl = stControl
+ chr(cnCarriageReturn)
+ chr(cnLineFeed)
endFor
switch
case dpi.DocumentSpacingAfter = True :
dpi.DocumentContent = dpi.DocumentContent
+ stControl
otherwise :
dpi.DocumentContent = stControl
+ dpi.DocumentContent
endSwitch
endSwitch
;
; Check for a form feed
;
switch
case dpi.DocumentFormFeed = False :
case dpi.DocumentFormFeedAfter = False :
dpi.DocumentContent = chr(cnFormFeed)
+ dpi.DocumentContent
otherwise :
dpi.DocumentContent = dpi.DocumentContent
+ chr(cnFormFeed)
endSwitch
liSize = dpi.DocumentContent.size()
liAny = 0
;
; Send the data to the printer
;
liReturn = WritePrinter(
dpi.PrinterHandle,
dpi.DocumentContent,
liSize,
liAny)
dpi.BytesWritten = dpi.BytesWritten
+ liAny
loReturn = (liReturn = 1)
return loReturn
endMethod
method ClosePrinterDirect(var dpi W32DirectPrintInfo) Logical
var
liReturn LongInt
endVar
;
; End printer session and release resources
;
liReturn = EndPagePrinter(dpi.PrinterHandle)
liReturn = EndDocPrinter(dpi.PrinterHandle)
liReturn = ClosePrinter(dpi.PrinterHandle)
liReturn = GlobalFree(dpi.DocumentStructure)
return True
endMethod
Example:Output ten lines on two pages double spaced. Assume that PW32Prnt is opened for library PW32Prnt.lsl. var
dpi W32DirectPrintInfo
siLine SmallInt
endVar
dpi.Printer = "Your Windows Printer Name goes here"
dpi.DocumentName = "Paradox Print Direct "
switch
case PW32Prnt.OpenPrinterDirect(dpi) = False :
msgStop("Error","Cannot open printer for direct access")
otherwise :
setMouseShape(MouseWait)
dpi.DocumentSpacing = 2
for siLine from 1 to 10
switch
case siLine = 5 :
dpi.DocumentFormFeed = True
otherwise :
dpi.DocumentFormFeed = False
endSwitch
dpi.DocumentContent = "Line "
+ strval(siLine)
+ " - This is a test for direct printing."
PW32Prnt.WritePrinterDirect(dpi)
endFor
PW32Prnt.ClosePrinterDirect(dpi)
setMouseShape(MouseArrow)
endSwitch
Conclusion We now have methods that provide direct access to Windows printers. Next: Changing Printer Attributes |
| < Prev | Next > |
|---|





