1
votes

Actually I am working with Qt printing and need to send the RAW command (ESCP command) to printer. After did some search and I found that I need to use the Windows API to do it.

Refer to this thread : win32-c-print-string-to-printer

I have created the code like below :

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;

And the code failed on StartDocPrinter, it returning 0 which mean failed. And using the GetLastError(), the function return 1804. And refer to this, the error is ERROR_INVALID_DATATYPE. I am not sure what error is it. And i try to use different DocInfo.pDatatype to "RAW", "TEXT", and "XPS_PASS", the result is the same.

Is there anything I can do how to fix it?

1
1. You likely need to deal with UNICODE version of Win32 API for correctly passing string data from Qt. For that end each Win32 function name with W capital when applicable e.g. OpenPrinterW.Alexander V
2. The way to produce lpData is way too confusing. It seems to me that you implicitly have W wide Win32 API function call there while feeding WritePrinterF with 8 bit char.Alexander V
As documented in MSDN, StartDocPrinter() does not set the last error. So using GetLastError() just gets you a bewildering random number. Standard with any winapi having to do with printing, it is the job of the printer driver to generate meaningful errors. Of which there are entirely too many of, that's why you can only get an "it did not work" status code. Not getting anything useful out a printer driver, yeah, that happens. Cut-throat business, no money for good devs and all. Look for anything in the Application event log.Hans Passant
WritePrinter is the only version of API function, no wide version. But check on whether 'wide' char string argument is needed.Alexander V
They are using TCHAR and using it correctly; I don't think wide strings are the issue. The weird string casting when setting DocInfo is straight out of MSDN. They do seem to be jumping through a lot of unnecessary hoops to get the data they want to send, though; const BYTE *lpData = (const BYTE *) "\x1b@Is it works?" should be sufficient. But that shouldn't be the issue either (the string is already valid UTF-8, so the byte array should be identical).andlabs

1 Answers

0
votes
DOC_INFO_1 DocInfo;
DocInfo.pDocName = (LPTSTR)_T("My Document");
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = (LPTSTR)_T("RAW");

This casting boils down to

DocInfo.pDocName = (wchar_t*)L"My Document";
...

Where pDocName is declared as wchar_t* This is wrong and the cast simply hides the errors and warnings. Try to avoid Microsoft T macro altogether, these macros are outdated and useless. Use C++ char and wchar_t* instead. To declare UTF16 wide char string in Windows, use the L prefix. The correct usage is as follows:

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;

Example:

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);
}