如何让Win32 API的PrintDlg返回选中打印机的信息?
问题:PrintDlg函数仅返回默认打印机信息,无法获取选中打印机的信息
我正在测试一个使用Win32 API打印发票的动态链接库,目前发票绘制正常,但PrintDlg函数仅返回默认打印机的信息。请问有没有办法让PrintDlg函数返回选中打印机的信息?
精简版调用代码
//Variable declarations PRINTDLGA *tmpprintdlg = 0; char *tmpstr = 0; char *tmpstr2 = 0; char *tmpstr3 = 0; DEVNAMES *tmpdevnames = 0; DEVMODEA *tmpdevmode = 0; HDC tmphdc = 0; int ret = 0; int ret2 = 0; //Show the print dialog. ret = PrntShowPrintDialog(GLB_HWndMainDialog, &tmpprintdlg); if((ret != TSUCCESS) && \ (ret != FALSE)){ //Get the error string. PrntGetErrorString(&tmpstr); MessageBox(NULL, tmpstr, "Error", MB_OK); return FALSE; } //EndIf //Check if the user cancelled the print. if(ret == FALSE){ //Returns return FALSE; } //EndIf //Get the selected printer. tmpdevnames = (DEVNAMES*)GlobalLock(tmpprintdlg->hDevNames); //Use the members in the device names pointer //to get information about the printer. //Set tmpn to zero. tmpn = 0; //Get the name of the printer driver. tmpn = tmpdevnames->wDriverOffset; tmpstr = (char*)(((char*)tmpdevnames) + tmpn); //Get the name of the printer. tmpn = tmpdevnames->wDeviceOffset; tmpstr2 = (char*)(((char*)tmpdevnames) + tmpn); //Get the name of the printer port. tmpn = tmpdevnames->wOutputOffset; tmpstr3 = (char*)(((char*)tmpdevnames) + tmpn); //Get the device mode for the printer. if(tmpprintdlg->hDevMode != NULL){ tmpdevmode = (DEVMODEA*)GlobalLock(tmpprintdlg->hDevMode); } //EndIf //Create a device context for the user selected //printer. tmphdc = CreateDCA(tmpstr, tmpstr2, tmpstr3, tmpdevmode); if(tmphdc == NULL){ //Get the last Win32 error. ret2 = GetLastError(); //Create an error string. PrntCreateErrorString(ret2, \ TCREATEFAILED, \ "CreateDC", \ &tmpstr); //Show the error string. MessageBox(NULL, \ tmpstr, \ "Error", \ MB_OK); //Returns return FALSE; } //Unlock the tmpdevnames memory. GlobalUnlock(tmpdevnames); //Unlock the tmpdevmode memory. if(tmpdevmode != NULL){ GlobalUnlock(tmpdevmode); } //EndIf
PrntShowPrintDialog函数实现
TRESULT PrntShowPrintDialog(_IN HWND inobj, \ _INOUT PRINTDLGA **outobj){ //Variable declarations PRINTDLGA *tmpprintdlg = 0; HWND tmphndwindow = 0; HINSTANCE tmphinst = 0; int ret = 0; int ret2 = 0; //Allocate memory to one PRINTDLGA object. tmpprintdlg = (PRINTDLGA*)calloc(1024, sizeof(char)); if(tmpprintdlg == NULL){ //Create an error string and set the //global static variable. PrntCreateErrorString(0, TMEMALLOCFAILED, "calloc", NULL); //Returns return TMEMALLOCFAILED; } //EndIf //Set some members in the PRINTDLGA object. tmpprintdlg->lStructSize = sizeof(PRINTDLGA); tmpprintdlg->hwndOwner = tmphndwindow; tmpprintdlg->hDevMode = NULL; tmpprintdlg->hDevNames = NULL; tmpprintdlg->hDC = NULL; tmpprintdlg->Flags = PD_ALLPAGES | \ PD_ENABLEPRINTHOOK | \ PD_ENABLESETUPHOOK | \ PD_NONETWORKBUTTON | \ PD_NOSELECTION | \ PD_COLLATE | \ PD_RETURNDC; tmpprintdlg->nMinPage = 0; tmpprintdlg->nMaxPage = 200; tmpprintdlg->nCopies = 1; tmpprintdlg->hInstance = tmphinst; tmpprintdlg->lCustData = NULL; tmpprintdlg->lpfnPrintHook = PrntDlgPrintProc; tmpprintdlg->lpfnSetupHook = PrntDlgSetupProc; tmpprintdlg->lpPrintTemplateName = NULL; tmpprintdlg->lpSetupTemplateName = NULL; tmpprintdlg->hPrintTemplate = NULL; tmpprintdlg->hSetupTemplate = NULL; //Show the print dialog box. This //is a modal dialog. ret = PrintDlg(tmpprintdlg); //Returns *outobj = tmpprintdlg; if(ret == 0){ return FALSE; }else{ return TSUCCESS; } //EndIf } //End PrntShowPrintDialog
补充说明
钩子过程的两个回调函数PrntDlgPrintProc和PrntDlgSetupProc是仅返回TSUCCESS的哑函数。
- 选择前:对话框显示默认打印机信息
- 选择后:已在对话框中选中其他打印机,但代码获取到的仍为默认打印机信息
问题原因及解决方法
核心问题
- 父窗口句柄未正确传递:
PrntShowPrintDialog中tmphndwindow初始化为0,未使用传入的inobj作为hwndOwner,导致对话框上下文异常,无法保存用户选择。 - 钩子函数返回值错误:Win32对话框钩子需返回系统约定值(如
FALSE让系统处理默认逻辑),自定义的TSUCCESS会干扰对话框流程,导致用户选择不被保存。 - 内存分配不规范:用
calloc(1024, sizeof(char))分配结构,虽当前足够,但更规范的方式是直接分配sizeof(PRINTDLGA)大小内存。
修正步骤
传递正确的父窗口句柄:
在PrntShowPrintDialog中,将tmpprintdlg->hwndOwner = tmphndwindow;改为:tmpprintdlg->hwndOwner = inobj;修正钩子函数返回值:
将两个哑钩子函数返回值改为FALSE,让系统处理默认消息流程:UINT_PTR CALLBACK PrntDlgPrintProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { return FALSE; } UINT_PTR CALLBACK PrntDlgSetupProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { return FALSE; }若不需要钩子功能,可直接移除
PD_ENABLEPRINTHOOK和PD_ENABLESETUPHOOK标志,避免不必要干扰。规范内存分配:
将tmpprintdlg = (PRINTDLGA*)calloc(1024, sizeof(char));改为:tmpprintdlg = (PRINTDLGA*)calloc(1, sizeof(PRINTDLGA));
验证修正
修改后,PrintDlg调用完成后,tmpprintdlg->hDevNames和tmpprintdlg->hDevMode会正确指向用户选中打印机对应的DEVNAMES和DEVMODE结构,后续通过GlobalLock获取的信息即为选中打印机的内容。
内容的提问来源于stack exchange,提问作者Thema Guishard
相关产品推荐
相关产品推荐

