实际上我正在使用Qt打印,需要将RAW命令(ESCP命令)发送到打印机。经过一番搜索,我发现我需要使用Windows API来完成它。
请参阅此线程:win32-c-print-string-to-printer
我创建了如下代码:
const QString pName = "EPSON LX-300+ /II";
LPBYTE lpData;
BOOL bStatus = FALSE;
HANDLE hPrinter = NULL;
DOC_INFO_1 DocInfo;
DWORD dwPrtJob = 0L;
DWORD dwBytesWritten = 0L;
LPTSTR printerName = new wchar_t[pName.length() + 1];
pName.toWCharArray(printerName);
printerName[pName.length()] = '\0';
QString so = "\x1b@Is it works?";
QByteArray ba = so.toUtf8();
lpData = (unsigned char*)(ba.data());
DWORD dwCount = ba.length();
qDebug() << so;
bStatus = OpenPrinter(printerName, &hPrinter, NULL);
if(bStatus) {
DocInfo.pDocName = (LPTSTR)_T("My Document");
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = (LPTSTR)_T("RAW");
dwPrtJob = StartDocPrinter (
hPrinter,
1,
(LPBYTE)&DocInfo);
qDebug() << GetLastError();
if (dwPrtJob > 0) {
qDebug() << "COMMAND";
// Send the data to the printer.
bStatus = WritePrinter (
hPrinter,
lpData,
dwCount,
&dwBytesWritten);
}
qDebug() << dwCount;
qDebug() << dwBytesWritten;
EndDocPrinter (hPrinter);
// Close the printer handle.
bStatus = ClosePrinter(hPrinter);
qDebug() << bStatus;
}
if (!bStatus || (dwCount != dwBytesWritten)) {
bStatus = FALSE;
} else {
bStatus = TRUE;
}
delete printerName;
代码在 StartDocPrinter 上失败,返回 0 表示失败。使用GetLastError(),函数返回1804。参考this,错误是ERROR_INVALID_DATATYPE。我不确定这是什么错误。我尝试对“RAW”、“TEXT”和“XPS_PASS”使用不同的DocInfo.pDatatype,结果是相同的。
有什么我可以解决的办法吗?
DOC_INFO_1 DocInfo;
DocInfo.pDocName = (LPTSTR)_T("My Document");
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = (LPTSTR)_T("RAW");
这个选角归结为
DocInfo.pDocName = (wchar_t*)L"My Document";
...
其中
pDocName
声明为 wchar_t*
这是错误的,强制转换只是隐藏了错误和警告。尽量完全避免 Microsoft T
宏,这些宏已经过时且无用。请改用 C++ char
和 wchar_t*
。要在 Windows 中声明 UTF16 宽字符字符串,请使用 L
前缀。正确的用法如下:
DOC_INFO_1 DocInfo;
wchar_t docName[100], dataType[100];
wcscpy_s(docName, 100, L"Print Job");
wcscpy_s(dataType, 100, L"RAW");
DocInfo.pDocName = docName;
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = dataType;
示例:
const QString pName = "EPSON LX-300+ /II";
wchar_t printerName[100];
pName.toWCharArray(printerName);
pName[pName.length()] = '\0';
HANDLE hprinter;
if (OpenPrinter(printerName, &hprinter, NULL))
{
DOC_INFO_1 DocInfo;
wchar_t docName[100], dataType[100];
wcscpy_s(docName, 100, L"Print Job");
wcscpy_s(dataType, 100, L"RAW");
DocInfo.pDocName = docName;
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = dataType;
DWORD printJob = StartDocPrinter(hprinter, 1, (LPBYTE)&DocInfo);
if (printJob && StartPagePrinter(hprinter))
{
MessageBox(0, L"StartPagePrinter OKAY", 0, 0);
DWORD written = 0;
int buflen = 100;
char *buf = new char[buflen];
strcpy_s(buf, buflen, "123");
if (WritePrinter(hprinter, buf, 3, &written))
MessageBox(0, L"OKAY", 0, 0);
delete[]buf;
EndPagePrinter(hprinter);
EndDocPrinter(hprinter);
}
ClosePrinter(hprinter);
}
这对我来说是有效的,可以将原始命令发送到斑马打印机,而无需复制所有缓冲区:
void rawDataToPrinter(QString text, QString printerName)
{
HANDLE hPrinter;
if (OpenPrinter(const_cast<wchar_t*>(printerName.toStdWString().c_str()), &hPrinter, nullptr))
{
wchar_t docName[] = L"Print Job";
wchar_t dataType[] = L"Raw";
// Fill in the structure with info about this "document."
DOC_INFO_1 docInfo;
docInfo.pDocName = docName;
docInfo.pOutputFile = nullptr;
docInfo.pDatatype = dataType;
// Inform the spooler the document is beginning.
DWORD printJob = StartDocPrinter(hPrinter, 1, reinterpret_cast<LPBYTE>(&docInfo));
if (printJob && StartPagePrinter(hPrinter))
{
DWORD dwBytesWritten;
if(!WritePrinter(hPrinter, const_cast<char*>(qPrintable(text)), static_cast<DWORD>(text.length()), &dwBytesWritten))
{
qDebug() << "Print job failed..";
}
else
{
qDebug() << "Job send to printed";
}
EndPagePrinter(hPrinter);
EndDocPrinter(hPrinter);
}
else
{
qDebug() << "Failed to open document or start page on printer " << printerName;
}
ClosePrinter(hPrinter);
}
else
{
qDebug() << "Failed to open printer " << printerName;
}
}