背景:
采用Qt的QPrinterInfo可获取到可用的打印机,同时使用QPrinter设置打印的纸张,单位,方向等信息,在正常连接打印机和纸张正确放置的情况下可以实现打印功能,开发所用的打印机为MITSUBISHI P95DW,当打印机无纸,离线或者关闭等其他异常情况下,Qt所获取到的打印机依然是IDLE状态了,无法获取到打印机真实的异常状态。
调试思考:
1.所用打印机弹出了Paper Empty的窗口,所以就想到用钩子获取到该窗口,并根据内容得到具体的异常内容,钩子的方法参见
,但是遗憾的是,当Windows桌面系统没有启用时,打印机的异常弹出窗口并没有产生。所以此方案行不通。
2.按照一般思路,Windows系统应该是捕捉了打印机通过驱动上发的异常消息,所以应该有API能够有这些功能。通过网络查找发现了EnumPrinters的函数,通过函数名可知是枚举打印机的,那么自然而然就能够有其他的函数能够找到获取打印机状态的函数了。
https://docs.microsoft.com/en-us/windows/win32/printdocs/enumprinters
结果:
通过查找和阅读文档中相对应的函数,找到了获取当前打印机状态的函数如:
OpenPrinter
GetPrinter
参数设置不同可以获取到不同级别的打印机当时的状态内容,本文使用的级别是2,对应到的结构体为
PRINTER_INFO_2;利用获取到的结构体的字段就可以知道对应的打印机状态
typedef struct _PRINTER_INFO_2 {
LPTSTR pServerName;
LPTSTR pPrinterName;
LPTSTR pShareName;
LPTSTR pPortName;
LPTSTR pDriverName;
LPTSTR pComment;
LPTSTR pLocation;
LPDEVMODE pDevMode;
LPTSTR pSepFile;
LPTSTR pPrintProcessor;
LPTSTR pDatatype;
LPTSTR pParameters;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD Attributes;
DWORD Priority;
DWORD DefaultPriority;
DWORD StartTime;
DWORD UntilTime;
DWORD Status;
DWORD cJobs;
DWORD AveragePPM;
} PRINTER_INFO_2, *PPRINTER_INFO_2;
代码如下,可用作参考
HANDLE hPrinter;
DWORD dwNeeded, dwReturne;
wchar_t wBuffer[256] = { 0 };
std::wstring wStr = m_pQPrinter->printerName().toStdWString();
wmemcpy_s(wBuffer, 256, wStr.c_str(), wStr.size());
LPWSTR lpw = wBuffer;
if (!OpenPrinter(lpw, &hPrinter, NULL))
{
return;
}
if (!GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
ClosePrinter(hPrinter);
return;
}
}
PRINTER_INFO_2 * pPrinterInfo = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (!pPrinterInfo)
{
//分配内存失败
ClosePrinter(hPrinter);
return;
}
if (!GetPrinter(hPrinter, 2, (LPBYTE)pPrinterInfo, dwNeeded, &dwReturne))
{
ClosePrinter(hPrinter);
//delete pJobInfo;
GlobalFree((HGLOBAL)pPrinterInfo);
return;
}
QString printStatus;
switch (pPrinterInfo->Status)
{
case PRINTER_STATUS_PAPER_OUT: {printStatus = QString(QObject::tr("Printer paper out")); }break;
case PRINTER_STATUS_OFFLINE:{printStatus = QString(QObject::tr("Printer offline"));}break;
case PRINTER_STATUS_PAUSED: {printStatus = QString(QObject::tr("Printer paused")); }break;
case PRINTER_STATUS_ERROR: {printStatus = QString(QObject::tr("Printer error")); }break;
case PRINTER_STATUS_PENDING_DELETION:break;
case PRINTER_STATUS_PAPER_JAM: {printStatus = QString(QObject::tr("Printer pager jam")); }break;
case PRINTER_STATUS_PAPER_PROBLEM: {printStatus = QString(QObject::tr("Printer pager problem")); }break;
case PRINTER_STATUS_BUSY: {printStatus = QString(QObject::tr("Printer busy")); }break;
case PRINTER_STATUS_PRINTING: {printStatus = QString(QObject::tr("Do printing")); }break;
case PRINTER_STATUS_OUTPUT_BIN_FULL:break;
case PRINTER_STATUS_NOT_AVAILABLE: {printStatus = QString(QObject::tr("Printer not available")); }break;
case PRINTER_STATUS_WAITING: {printStatus = QString(QObject::tr("Printer waiting")); }break;
case PRINTER_STATUS_OUT_OF_MEMORY: {printStatus = QString(QObject::tr("Printer out of memory")); }break;
case PRINTER_STATUS_DOOR_OPEN: {printStatus = QString(QObject::tr("Printer door open")); }break;
default: {ClosePrinter(hPrinter); return; }
break;
}
ClosePrinter(hPrinter);