笔者最近有需求要直接操作针式打印机也就是存折打印机。这种打印机一般用来套打或者打存折的。中文资料比较少,所以笔者去研究了下,顺便分享一下。
下面是msdn上关于打印机相关的函数介绍 https://docs.microsoft.com/en-us/windows/win32/printdocs/printing-and-print-spooler-functions#printer-functions。
笔者一开始的需求是 打印带格式的字符串,用CDC::TextOut的方式 ,该方式并不识别字符串中的换行格式,所以只能找其他方式。有3种方式可以直接向打印机发送数据。
Escape函数(https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-escape)
The Escape function enables an application to access the system-defined device capabilities that are not available through GDI. Escape calls made by an application are translated and sent to the driver.
int Escape(
HDC hdc,
int iEscape,
int cjIn,
LPCSTR pvIn,
LPVOID pvOut
);
The ExtEscape function enables an application to access device capabilities that are not available through GDI.
int ExtEscape(
HDC hdc,
int iEscape,
int cjInput,
LPCSTR lpInData,
int cjOutput,
LPSTR lpOutData
);
The WritePrinter function notifies the print spooler that data should be written to the specified printer.
BOOL WritePrinter(
_In_ HANDLE hPrinter,
_In_ LPVOID pBuf,
_In_ DWORD cbBuf,
_Out_ LPDWORD pcWritten
);
这3种函数,我们把打印机的带格式的字符串的数据直接发送给指定打印机,格式是能识别的,因为换行的二进制数据 在 存折打印机指令中就是识别为换行 所以可以正常打印带格式的字符串。vs2010的帮助文档上说可以用WritePrinter函数代码escape(This method can be used to replace the PASSTHROUGH escape and SpoolFile methods.)。下面这段代码是 MSDN上的例子,唯一的一个缺点是 在将字符串送给打印机打印完之后 打印机并未退纸,所以笔者 在打印字符串后添加了一个退纸的指令0x0c 。
//
// RawDataToPrinter - sends binary data directly to a printer
//
// szPrinterName: NULL-terminated string specifying printer name
// lpData: Pointer to raw data bytes
// dwCount Length of lpData in bytes
//
// Returns: TRUE for success, FALSE for failure.
//
BOOL RawDataToPrinter(LPTSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
{
BOOL bStatus = FALSE;
HANDLE hPrinter = NULL;
DOC_INFO_1 DocInfo;
DWORD dwJob = 0L;
DWORD dwBytesWritten = 0L;
// Open a handle to the printer.
bStatus = OpenPrinter( szPrinterName, &hPrinter, NULL );
if (bStatus) {
// Fill in the structure with info about this "document."
DocInfo.pDocName = (LPTSTR)_T("My Document");
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = (LPTSTR)_T("RAW");
// Inform the spooler the document is beginning.
dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo );
if (dwJob > 0) {
// Start a page.
bStatus = StartPagePrinter( hPrinter );
if (bStatus) {
// Send the data to the printer.
bStatus = WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten);
DWORD dwBytesWritten2 = 0L;
BYTE b[1] = {0xc}; // 退纸
bStatus = WritePrinter( hPrinter, &b,1 , &dwBytesWritten2);
EndPagePrinter (hPrinter);
}
// Inform the spooler that the document is ending.
EndDocPrinter( hPrinter );
}
// Close the printer handle.
ClosePrinter( hPrinter );
}
// Check to see if correct number of bytes were written.
if (!bStatus || (dwBytesWritten != dwCount)) {
bStatus = FALSE;
} else {
bStatus = TRUE;
}
return bStatus;
}