PrintDlgEx调用返回E_INVALIDARG错误,PrintDlg正常工作求排查
问题
项目中需要使用PrintDlgEx,但无论采用何种参数组合(包括微软官方示例的配置),调用后始终返回E_INVALIDARG错误。换成PRINTDLG结构体和PrintDlg函数(移除PrintDlgEx专属参数)就能正常运行。
因为设计和预览需求,必须用PrintDlgEx来获取Apply按钮功能,实现不打印时修改打印机或属性表的需求。
以下是简化后的测试代码,目前无法弹出对话框,求排查原因:
#include <QDebug> #include <QWindow> #include <windows.h> void showPrintDialog() { // Simplifying the setup: real code passes in a QWidget * QWidget *caller = this; // Not returning a value or doing any work. I just want the dialog to pop up for now // Create the standard windows print dialog PRINTDLGEX printDialog; memset(&printDialog, 0, sizeof(PRINTDLGEX)); printDialog.lStructSize = sizeof(PRINTDLGEX); printDialog.Flags = PD_RETURNDC | // Return a printer device context. Without this, HDC may be undefined PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION | // Don't allow selecting individual document pages to print PD_NOPAGENUMS | // Disables some boxes PD_NOCURRENTPAGE | // Disables some boxes PD_NONETWORKBUTTON | // Don't allow networking (but it show "Find printer") so what does this do ? PD_HIDEPRINTTOFILE; // Don't allow print to file // Only on PRINTDLGEX // Theis block copied from https://learn.microsoft.com/en-us/windows/win32/dlgbox/using-common-dialog-boxes?redirectedfrom=MSDN // I have tried multiple combinations of options, including none, I really don't want any of them printDialog.nStartPage = START_PAGE_GENERAL; printDialog.nPageRanges = 1; printDialog.nMaxPageRanges = 10; LPPRINTPAGERANGE pageRange = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE)); printDialog.lpPageRanges = pageRange; printDialog.lpPageRanges[0].nFromPage = 1; printDialog.lpPageRanges[0].nToPage = 1; printDialog.Flags2 = 0; printDialog.ExclusionFlags = 0; printDialog.dwResultAction = 0; // This will tell me if PRINT // Rest of options are also on PRINTDLG printDialog.nMinPage = 1; printDialog.nMaxPage = 10; // The only options I really need printDialog.nCopies = 1; printDialog.hDevMode = Q_NULLPTR; // which will be better once this works printDialog.hDevNames = Q_NULLPTR; // which will be better once this works printDialog.hwndOwner = reinterpret_cast<HWND>(caller->windowHandle()->winId()); // Calling... int result = PrintDlgEx(&printDialog); qDebug() << (result == E_INVALIDARG ? "Invalid Argument" : "Success"); // It always is E_INVALIDARG // Cleanup if (printDialog.hDevMode) GlobalFree(printDialog.hDevMode); if (printDialog.hDevNames) GlobalFree(printDialog.hDevNames); if (printDialog.hDC) DeleteDC(printDialog.hDC); }
平台信息:Windows 10最新版本;Qt版本5.12.7及以上(测试环境为5.15.1)
排查与解决
核心问题
你设置的Flags中包含PD_NOPAGENUMS,但同时又初始化了nPageRanges、lpPageRanges等页码范围相关参数,这两者冲突。PD_NOPAGENUMS的作用是禁用页码选择功能,此时系统不允许提供页码范围数据,否则会直接返回E_INVALIDARG错误。
修复方案
任选以下一种方式修改:
- 移除
PD_NOPAGENUMS标志,保留页码范围参数(适合需要用户选择页码的场景) - 保留
PD_NOPAGENUMS,同时删除所有页码范围相关的初始化代码(包括nStartPage、nPageRanges、nMaxPageRanges、lpPageRanges的分配与赋值)
额外注意事项
- 代码中用
GlobalAlloc分配的pageRange未在清理阶段释放,需添加GlobalFree(pageRange);避免内存泄漏。 - 确认
caller->windowHandle()->winId()能获取到有效HWND,可通过qDebug()输出该值验证是否非空。
修改后的示例代码(保留PD_NOPAGENUMS的情况)
#include <QDebug> #include <QWindow> #include <windows.h> void showPrintDialog() { QWidget *caller = this; PRINTDLGEX printDialog; memset(&printDialog, 0, sizeof(PRINTDLGEX)); printDialog.lStructSize = sizeof(PRINTDLGEX); printDialog.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION | PD_NOCURRENTPAGE | PD_NONETWORKBUTTON | PD_HIDEPRINTTOFILE; // 移除所有页码范围相关参数的初始化 printDialog.Flags2 = 0; printDialog.ExclusionFlags = 0; printDialog.dwResultAction = 0; printDialog.nMinPage = 1; printDialog.nMaxPage = 10; printDialog.nCopies = 1; printDialog.hDevMode = Q_NULLPTR; printDialog.hDevNames = Q_NULLPTR; printDialog.hwndOwner = reinterpret_cast<HWND>(caller->windowHandle()->winId()); int result = PrintDlgEx(&printDialog); qDebug() << (result == E_INVALIDARG ? "Invalid Argument" : "Success"); // 清理资源 if (printDialog.hDevMode) GlobalFree(printDialog.hDevMode); if (printDialog.hDevNames) GlobalFree(printDialog.hDevNames); if (printDialog.hDC) DeleteDC(printDialog.hDC); }
内容的提问来源于stack exchange,提问作者Thalia
相关产品推荐
相关产品推荐

