The information in this article applies to:
- Standard and Professional Editions of Microsoft Visual Basic for
Windows, versions 2.0 and 3.0
SUMMARY
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:
ARTICLE-ID: Q96795
TITLE : Using 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 F5 to run the program and it prints out the file
C:\TMP\DATA.PRN for you.
REFERENCES
See the following Microsoft Knowledge Base article from the WinSDK
database:
ARTICLE-ID: Q111010
TITLE : INF: An Alternative to SpoolFile()
|