One of the frequently asked questions on the VB-related CompuServe forums is ‘how do I send printer codes directly to my printer’? Most posters have already tried something like ‘Printer.Print Chr$(27) & "some escape code"’, only to discover that the entire escape sequence appears on paper, instead of being interpreted by the printer. This happens because Windows is page-oriented and ‘draws’ all characters you want to print onto a printer device context (loosely translated: a page) and is not stream-oriented like DOS, which basically treated a printer like a special kind of file.
To work around this problem, I wrote the PrintBinaryFile function, a full-featured version of some code I already used myself to print pre-formatted files to a HP Laserjet printer. An enhanced version of the function (PR2FILE.MAK) is included with this article: let’s take a look at some parts of it.
One of the very first things we need to do before using PrintBinaryFile is determining the operating system we’re running on. Windows NT and Windows 95 contain a very handy library called ‘WinSpool’ that helps us work around a minor problem that PrintBinaryFile has when running on Windows 3.1: the need for a (hardcoded) printer driver filename. PrintBinaryFile needs to call the ExtDeviceMode function, which is contained in the printer driver file, and as VB is needs to know the exact name of each library, you’ll need to hard-code this driver file name. This is not really a problem, as the output you’ll be generating is printer-dependent anyway, and you’ll be able to make assumptions about the driver without much problems. When running on Windows NT or Windows 95, we can use the ExtDeviceMode function in the WinSpool driver, which on NT is called WinSpool.DRV and WinSpl16.DRV on Windows 95. Please note that I got reports of GPFs when using WinSpl16 on some builds of Windows 95: unless your testing shows it works OK, you might want to treat this version in the same way as Windows 3.1.
The actual PrintBinaryFile function takes four parameters: Fil$, the fully qualified DOS filename of the file you want to print, DOSDevice$, the DOS device name (f.e. LPT1: or \SERVERPRINTER) for the printer device, DocName$, the description for the document that will show up in the Print Manager and DocFile$, in case you want to print to a file. The last parameter doesn’t make any real sense, as you will already have got a file if you want to use PrintBinaryFile, but it might be useful in other situations. PrintBinaryFile first looks up the DOS device you specify in WIN.INI (or the Registry emulation therof provided by NT) to find out the name of the printer driver. This driver is subsequently loaded into memory using the LoadLibrary API call.
Next, ExtDeviceMode is used to retrieve the Device Mode structure for the printer and to make any required changes to that. Next, a Device Context is created, which we is then used to write the output to using the ‘PASSTHROUGH’ printer escape. By using this escape function, Windows does not interpret the data we send at all, but just passes it on to the device, which is exactly the point of PrintBinaryFile. Some device drivers don’t support this escape function, in which case an error message is displayed. You should be able to work around this by simply using a different device driver: since it plays no part in interpreting the data, it doesn’t have to match the output device at all.
The file is sent to the driver in a loop that uses 8K blocks: trying to send the entire file at once would probably exhaust VB’s string resources. If speed is important to you, you might want to increase the block size to the highest possible value. Be aware, though, that this could generate out-of-memory errors at some point: 8K should be a safe enough value. After the entire file is sent, PrintBinaryFile cleans up the resources it allocated and returns to the caller.
I hope this explanation and the code that goes with it is useful to you!
|