Recipe 11.2. Sending "Raw" Data to a PrinterProblemYou need to send unprocessed data directly to a printer or print spooler, without processing by a printer driver. SolutionSample code folder: Chapter 11\RawPrinterData The .NET Framework does not include direct support for this type of "raw" printing, so create your own class that uses various Win32 API calls. DiscussionThe .NET Framework does not include support for "raw" printing, the ability to send your own custom data directly to the printer. Some printers, such as barcode and receipt printers, accept data with embedded "escape sequences" that control the output on the printer. Many of these older printers do not include Windows drivers and can only be used in raw mode. To print to these printers from .NET, you must use a DLL commonly used in Visual Basic 6.0 development to send raw data and perform other low-level operations on printers. The winspool.drv library includes several useful printer-specific functions, including functions that let you open a channel to the printer directly and send raw data. Because this library is not a .NET library, you have to coax .NET through the communication process using the various options to the DllImport attribute that you attach to each library-call definition. The following code references the relevant public functions in this library and uses them to connect to the printer and send the requested data: Imports System.Runtime.InteropServices Public Class RawPrinter ' ----- Define the data type that supplies basic ' print job information to the spooler. <StructLayout(LayoutKind.Sequential, _ CharSet:=CharSet.Unicode)> _ Public Structure DOCINFO <MarshalAs(UnmanagedType.LPWStr)> _ Public pDocName As String <MarshalAs(UnmanagedType.LPWStr)> _ Public pOutputFile As String <MarshalAs(UnmanagedType.LPWStr)> _ Public pDataType As String End Structure ' ----- Define interfaces to the functions supplied ' in the DLL. <DllImport("winspool.drv", EntryPoint:="OpenPrinterW", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function OpenPrinter( _ ByVal printerName As String, ByRef hPrinter As IntPtr, _ ByVal printerDefaults As Integer) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="ClosePrinter", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function ClosePrinter( _ ByVal hPrinter As IntPtr) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="StartDocPrinterW", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function StartDocPrinter( _ ByVal hPrinter As IntPtr, ByVal level As Integer, _ ByRef documentInfo As DOCINFO) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="EndDocPrinter", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function EndDocPrinter( _ ByVal hPrinter As IntPtr) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="StartPagePrinter", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function StartPagePrinter( _ ByVal hPrinter As IntPtr) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="EndPagePrinter", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function EndPagePrinter( _ ByVal hPrinter As IntPtr) As Boolean End Function <DllImport("winspool.drv", EntryPoint:="WritePrinter", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function WritePrinter( _ ByVal hPrinter As IntPtr, ByVal buffer As IntPtr, _ ByVal bufferLength As Integer, _ ByRef bytesWritten As Integer) As Boolean End Function Public Shared Function PrintRaw( _ ByVal printerName As String, _ ByVal origString As String) As Boolean ' ----- Send a string of raw data to the printer. Dim hPrinter As IntPtr Dim spoolData As New DOCINFO Dim dataToSend As IntPtr Dim dataSize As Integer Dim bytesWritten As Integer ' ----- The internal format of a .NET String is just ' different enough from what the printer expects ' that there will be a problem if we send it ' directly. Convert it to ANSI format before ' sending. dataSize = origString.Length() dataToSend = Marshal.StringToCoTaskMemAnsi(origString) ' ----- Prepare information for the spooler. spoolData.pDocName = "My Visual Basic .NET RAW Document" spoolData.pDataType = "RAW" Try ' ----- Open a channel to the printer or spooler. Call OpenPrinter(printerName, hPrinter, 0) ' ----- Start a new document and Section 1.1. Call StartDocPrinter(hPrinter, 1, spoolData) Call StartPagePrinter(hPrinter) ' ----- Send the data to the printer. Call WritePrinter(hPrinter, dataToSend, _ dataSize, bytesWritten) ' ----- Close everything that we opened. EndPagePrinter(hPrinter) EndDocPrinter(hPrinter) ClosePrinter(hPrinter) Catch ex As Exception MsgBox("Error occurred: " & ex.ToString) Finally ' ----- Get rid of the special ANSI version. Marshal.FreeCoTaskMem(dataToSend) End Try End Function End Class This class includes all shared members, so just call them directly without creating an instance. Use the PrintRaw method by passing it a printer name and raw data to send: RawPrinter.PrintRaw("MyPrinter", _ "Hello, this is a test." & vbCrLf) You can use this to send data to network printers by supplying a printer path in the format \\SystemName\PrinterName. See AlsoThe code in this recipe is based on a Microsoft-supplied Knowledge Base article. On the MSDN web site (http://msdn.microsoft.com), access article number 322090 for additional details on using the winspool.drv file from .NET. |