Microsoft KB Archive/119113

From BetaArchive Wiki

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.

  1. Start a New Project in Visual Basic; form1 is created by default.
  2. 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
                        
  3. 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
                        
  4. 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.

  1. In Visual Basic, start a new project; form1 is created by default.
  2. 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
                        
  3. 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