Article ID: 119113
Article Last Modified on 7/13/2004
APPLIES TO
- Microsoft Visual Basic 2.0 Standard Edition
- Microsoft Visual Basic 3.0 Professional Edition
- Microsoft Visual Basic 2.0 Professional Edition
- Microsoft Visual Basic 3.0 Professional Edition
This article was previously published under Q119113
SUMMARY
NOTE: The following information does NOT apply to the 32-bit versions of Visual Basic.
This article discusses three methods for sending data or a preformatted file directly to the printer, thus bypassing the Windows printer driver:
- Using the Windows API Escape() with PASSTHROUGH
-or-
- Using the Windows API SpoolFile()
-or-
- Opening the printer port for binary file access
MORE INFORMATION
Applications written for Windows version 3.1 can use either the SpoolFile() function or the PASSTHROUGH printer escape to send a printer-specific file to Print Manager for spooling to a printer. In addition, Visual Basic allows you to open the printer port (lpt1, lpt2, etc.) as an MS-DOS device and send data directly to it. The following sections discuss each method.
Using the Windows API Escape() with PASSTHROUGH
Overall, the Escape() API works well. The major drawback is that not all printer drivers support it because it is considered obsolete. For additional information on how to implement this function, please see the following article in the Microsoft Knowledge Base:
96795 : How To Use PASSTHROUGH Escape to Send Data Directly to Printer
Using the Windows API SpoolFile()
The SpoolFile function puts a file into the spooler queue. This is useful when you have large files to print and you do not want to have your program handle all of the printing. The following is a list of known limitations of the Windows SDK SpoolFile() function:
- SpoolFile() is documented as being for use with local printers only. Using SpoolFile() with network printers results in undefined behavior; sometimes you may get output, sometimes you may get a general protection fault (GPF).
- Print Manager must be enabled (in the Printer Control Panel dialog box) for you to use SpoolFile().
- Print Manager treats the file exactly as it treats temporary files generated through "normal" GDI printing. This has two major effects:
- The file must use the correct language/format for the printer. Print Manager does not attempt to interpret or modify the file in any way, but simply writes the contents to the port.
- Print Manager deletes the file when done spooling it to the port.
- Finally, a bug in SpoolFile() causes Print Manager to cause a GPF when the application that called SpoolFile() terminates before Print Manager is done spooling the file to the port.
Despite these limitations, the API SpoolFile() is convenient and simple to use. Remember that SpoolFile() treats the file you send to it just like any other temporary file and deletes it when done. Therefore, if you need to preserve the file you want to print, you need to copy it. The code below provides an example of calling SpoolFile().
Before you run this sample, you need to have a preformatted file to print. You can create this by printing a document from Word and choosing the Print to File option. This sample assumes that C:\TMP\DATA.PRN is the file you want to print.
- Start a New Project in Visual Basic; form1 is created by default.
Place the following declarations in the General Declarations section of the form (each declaration needs to be on one line of code):
Declare Function SpoolFile Lib "GDI" (ByVal lpszPrinter As String, ByVal lpszPort As String, ByVal lpszJob As String, ByVal lpszFile As String) As Integer Declare Function GetProfileString Lib "Kernel" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Integer) As Integer
Add a command button (Command1) to the form and place the following code in the Click() event:
Sub Command1_Click () Dim DefaultPrinter As String 'hold the default printer information Dim Driver As String 'holds driver name Dim Port As String 'holds printer port of driver Dim FileToSpool As String 'name of file we are going to print Dim ret As Integer 'return value of API calls 'initialize our printer buffer, call the API, and trim the Nulls DefaultPrinter = Space$(128) 'the following statement needs to be on one line of code ret = GetProfileString("windows", "device", "NONE", DefaultPrinter, Len(DefaultPrinter)) DefaultPrinter = Left$(DefaultPrinter, ret) 'parse the printer line 'for the port, look for the second comma, this is where the port is 'for the printer driver, take the string up to the first comma Driver = Left$(DefaultPrinter, InStr(DefaultPrinter, ",") - 1) Port = Mid$(DefaultPrinter, InStr(Len(Driver) + 2, DefaultPrinter, ",") + 1) 'copy our data file and print the copy - SpoolFile will DELETE it! FileToSpool = "c:\tmp\toprintr.prn" FileCopy "c:\tmp\data.prn", FileToSpool 'the data file is data.prn 'spool the file to the PrintManager ret = SpoolFile(Driver, Port, App.Title & "-Spooling File", FileToSpool) 'check for errors (values in the Win 3.1 SDK help file If ((ret < -5) Or (ret > 0)) And (ret <> &H4000) Then MsgBox "File Spooled-Don't Quit until PrintManager is done printing!" Else MsgBox "Error on print: (" & CStr(ret) & ")" End If End Sub
- When you run the program and choose the command button, the program will print the file C:\TMP\DATA.PRN to the default printer.
Opening the Printer Port for Binary File Access
Using this method is much the same as implementing printer escape sequences in a Visual Basic for MS-DOS or QBasic applications. The advantages and disadvantages of this method are listed below:
- No Windows API functions are used.
- This method prints to the MS-DOS device LPTx, which can be redirected by your network.
- Your program handles all the printing.
- This method is not supported under Windows NT.
Below is a sample program that opens an input file and the printer port, "lpt1", for binary file access. The program then grabs an 8K chunk of data from the input file and sends it directly to the printer, looping until it reaches the end of file.
- In Visual Basic, start a new project; form1 is created by default.
Add a command button (Command1) to the form, and place the following code in the click event:
Sub Command1_Click () Const MaxSize = 8192 'max buffer size Dim Chunk As String 'buffer to hold data Dim numLoops As Long 'number of 8k loops Dim LeftOver As Integer 'amount of file left Dim i As Integer 'counter for loops 'open our datafile and printer port Open "c:\tmp\data.prn" For Binary As #1 Open "lpt1" For Binary As #2 'calculate size of file and amount left over numLoops = LOF(1) \ MaxSize LeftOver = LOF(1) Mod MaxSize 'initialize variables and loop Chunk = Space$(MaxSize) For i = 1 To numLoops Get #1, , Chunk Put #2, , Chunk Next 'grab what's leftover Chunk = Space$(LeftOver) Get #1, , Chunk Put #2, , Chunk 'close all our open files Close #2 Close #1 End Sub
- Press the F5 key to run the program and it prints out the file C:\TMP\DATA.PRN for you.
REFERENCES
For information on using the Win32 API to send information directly to the printer, see the following article in the Microsoft Knowledge Base:
154078 How To Send Raw Data to a Printer Using the Win32 API from Visual Basic
See the following Microsoft Knowledge Base article from the WinSDK database:
111010 How To Use PASSTHROUGH As An Alternative to SpoolFile()
Additional query words: kbVBp300 kbNoKeyWord kbVBp200
Keywords: kbhowto KB119113