【发布时间】:2016-06-24 22:27:51
【问题描述】:
实际上我正在使用 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。我不确定它是什么错误。我尝试使用不同的 DocInfo.pDatatype 到“RAW”、“TEXT”和“XPS_PASS”,结果是一样的。
有什么办法可以解决吗?
【问题讨论】:
-
1.您可能需要处理 UNICODE 版本的 Win32 API 才能正确地从 Qt 传递字符串数据。为此,每个 Win32 函数名称在适用时都带有 W 大写字母,例如OpenPrinterW。
-
2.产生 lpData 的方式太混乱了。在我看来,您在向 WritePrinterF 提供 8 位字符时隐式调用了 W 宽 Win32 API 函数。
-
如 MSDN 中所述,StartDocPrinter() not 设置了最后一个错误。所以使用 GetLastError() 只会得到一个令人眼花缭乱的随机数。任何与打印有关的 winapi 都是标准的,生成有意义的错误是打印机驱动程序的工作。其中完全太多了,这就是为什么您只能获得“它不起作用”状态代码的原因。没有从打印机驱动程序中得到任何有用的东西,是的,这种情况发生了。残酷的业务,优秀的开发人员没有钱。在应用程序事件日志中查找任何内容。
-
WritePrinter 是 API 函数的唯一版本,没有宽版本。但请检查是否需要“宽”字符字符串参数。
-
他们正在使用 TCHAR 并正确使用它;我不认为宽字符串是问题。设置
DocInfo时奇怪的字符串转换是straight out of MSDN。不过,他们似乎确实跳过了许多不必要的障碍来获取他们想要发送的数据;const BYTE *lpData = (const BYTE *) "\x1b@Is it works?"应该足够了。但这也不应该是问题(字符串已经是有效的 UTF-8,所以字节数组应该是相同的)。