【问题标题】:Windows GDI Printer error StartDocPrinterWindows GDI 打印机错误 StartDocPrinter
【发布时间】: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,所以字节数组应该是相同的)。

标签: c++ qt winapi printing


【解决方案1】:
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++ charwchar_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);
}

【讨论】:

  • 它可以工作,但我需要添加此代码 printerName[pName.length()] = '\0';在 pName.toWCharArray(printerName); 之后
  • 对,我忘了。我编辑问题以解决它。
猜你喜欢
  • 2017-01-26
  • 2019-11-23
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
相关资源
最近更新 更多