You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++(MFC)非模态调用默认打印机无法修改打印方向问题

问题

环境:Windows 10、Visual Studio 2017,使用C++(MFC)开发程序。
程序收到硬件触发信号时执行打印操作,当前打印功能正常,但需要实现检查页面方向,若为纵向则强制修改为横向的逻辑。

现有修改方向的代码片段:

CPrintDialog PrnDlg(FALSE);

if (PrnDlg.GetDefaults())
{
    DEV_MODE *pDevMode;

    pDevMode = (DEVMODE *)::GlobalLock(PrnDlg.m_pd.hDevMode);
    if (pDevMode->dmOrientation != DMORIENT_LANDSCAPE)
    {
        pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
    }
    ::GlobalUnlock(PrnDlg.m_pd.hDevMode);
    // 其他未展示代码
}

问题:修改后默认打印机仍以纵向打印,换成PrnDlg.DoModal()则功能正常,请问遗漏了什么步骤?

补充的默认打印机打印代码(未包含所有修改方向的尝试):

DOCINFO DocInfo;    
CPrintInfo PrintInfo;     
PRINTDLG pd;
delete PrintInfo.m_pPD;

// 构造自定义CLPrintDlg实例并赋值
PrintInfo.m_pPD = new CLPrintDlg(this,
   snPageSetupPaperOrientation,
   snPageSetupPaperSize,
   snPageSetupPaperSource);

PrintInfo.m_bDocObject = FALSE;    
PrintInfo.m_dwFlags = 0;
PrintInfo.m_bDirect = FALSE;    
PrintInfo.m_bPreview = FALSE;

CPrintDialog PrnDlg(FALSE);    
if (PrnDlg.GetDefaults())
{
   CString StrTitle = _T("HISTOGRAM PRINTOUT");

   memset(&DocInfo, 0, sizeof(DOCINFO));
   DocInfo.cbSize = sizeof(DOCINFO);
   DocInfo.lpszDocName = StrTitle;
   DocInfo.lpszOutput = NULL;

   CDC dcPrint;

   dcPrint.Attach(PrnDlg.m_pd.hDC);
   dcPrint.m_bPrinting = TRUE;
   dcPrint.StartDoc(&DocInfo);

   int nYRes = dcPrint.GetDeviceCaps(VERTRES);
   int nXRes = dcPrint.GetDeviceCaps(HORZRES);

   dcPrint.SetMapMode(MM_HIMETRIC);

   CSize size;
   size.cx = nPageSetupLeftMargin;
   size.cy = nPageSetupTopMargin;
   dcPrint.HIMETRICtoDP(&size);
   int nLeftMarg = size.cx;
   int nTopMarg = size.cy;

   size.cx = nPageSetupRightMargin;
   size.cy = nPageSetupBottomMargin;
   dcPrint.HIMETRICtoDP(&size);
   int nRightMarg = size.cx;
   int nBottomMarg = size.cy;

   int nXAvailable = nXRes - nLeftMarg - nRightMarg;
   int nYAvailable = nYRes - nTopMarg - nBottomMarg;

   dcPrint.SetMapMode(MM_ANISOTROPIC);

   dcPrint.StartPage();

   int nHeaderHeight = (int)(nYAvailable * HEADER_HEIGHT);
   int nMargBetweenHeaderAndHistogram = (int)(nYAvailable * 
                                  MARG_BETWEEN_HEADER_AND_HISTOGRAM);
   int nHistogramHeight = (int)(nYAvailable * HISTOGRAM_HEIGHT);
   int nMargBetweenHistogramAndLineReel = (int)(nYAvailable * 
                                  MARG_BETWEEN_HISTOGRAM_AND_LINE_REEL);
   int nLineReelHeight = (int)(nYAvailable * LINE_REEL_HEIGHT);
   int nMargBetweenLineReelAndData = (int)(nYAvailable * 
                                       MARG_BETWEEN_LINE_REEL_AND_DATA);
   int nDataHeight = (int)(nYAvailable * DATA_HEIGHT);
   int nMargBetweenDataAndFooter = (int)(nYAvailable * 
                                         MARG_BETWEEN_DATA_AND_FOOTER);
   int nFooterHeight = (int)(nYAvailable * FOOTER_HEIGHT);
   int nYOffset = nTopMarg;

   dcPrint.SetWindowExt(nXAvailable, nHeaderHeight);
   dcPrint.SetViewportExt(nXAvailable, nHeaderHeight);
   dcPrint.SetViewportOrg(nLeftMarg, nYOffset);
   pReelHeaderWnd->Print(dcPrint);

   nYOffset += nHeaderHeight + nMargBetweenHeaderAndHistogram;
   dcPrint.SetWindowExt(nXAvailable, nHistogramHeight);
   dcPrint.SetViewportExt(nXAvailable, nHistogramHeight);
   dcPrint.SetViewportOrg(nLeftMarg, nYOffset);
   pReelViewWnd->ShowPileWidthButtons(false);
   pReelViewWnd->Print(dcPrint);      
   pReelViewWnd->ShowPileWidthButtons(true);

   nYOffset += nHistogramHeight + nMargBetweenHistogramAndLineReel;
   dcPrint.SetWindowExt(nXAvailable, nLineReelHeight);
   dcPrint.SetViewportExt(nXAvailable, nLineReelHeight);
   dcPrint.SetViewportOrg(nLeftMarg, nYOffset);
   pLineReelInfoWnd->Print(szLineName, szReelId, dcPrint);

   nYOffset += nLineReelHeight + nMargBetweenLineReelAndData;
   dcPrint.SetWindowExt(nXAvailable, nDataHeight);
   dcPrint.SetViewportExt(nXAvailable, nDataHeight);
   dcPrint.SetViewportOrg(nLeftMarg, nYOffset);
   CRect rect(0, 0, nXAvailable, nDataHeight);
   //dcPrint.Rectangle( rect ); // Debug
   pReelDataWnd->Print(dcPrint);

   nYOffset += nDataHeight + nMargBetweenDataAndFooter;
   dcPrint.SetWindowExt(nXAvailable, nFooterHeight);
   dcPrint.SetViewportExt(nXAvailable, nFooterHeight);
   dcPrint.SetViewportOrg(nLeftMarg, nYOffset);
   //dcPrint.Rectangle( 0,0, nXAvailable, nFooterHeight ); // Debug
   pReelFooterWnd->Print(CLConfig::szCompanyName, dcPrint);

   dcPrint.EndPage();
   dcPrint.EndDoc();
}
解决方案

遗漏的核心步骤是修改DEVMODE后,没有标记字段变更,也未将DEVMODE的修改同步到打印DC。DoModal()内部会自动处理DEVMODE到DC的同步流程,但GetDefaults()仅初始化默认参数,需手动补充以下操作:

  1. 修改DEVMODE的dmOrientation后,必须设置dmFields标记,表明dmOrientation字段已被修改
  2. 调用ResetDC()将修改后的DEVMODE应用到打印对话框的DC上

修改后的完整方向调整代码:

CPrintDialog PrnDlg(FALSE);

if (PrnDlg.GetDefaults())
{
    DEVMODE* pDevMode = reinterpret_cast<DEVMODE*>(::GlobalLock(PrnDlg.m_pd.hDevMode));
    if (pDevMode)
    {
        if (pDevMode->dmOrientation != DMORIENT_LANDSCAPE)
        {
            pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
            // 标记方向字段已修改
            pDevMode->dmFields |= DM_ORIENTATION;
        }
        // 将修改后的DEVMODE同步到打印DC
        ::ResetDC(PrnDlg.m_pd.hDC, pDevMode);
        ::GlobalUnlock(PrnDlg.m_pd.hDevMode);
    }

    // 后续打印代码...
}

额外注意事项:

  • 确保PrnDlg.m_pd.hDC有效(GetDefaults()成功后会初始化该句柄)
  • 修改完成后必须调用GlobalUnlock()释放全局内存块,避免内存泄漏

内容的提问来源于stack exchange,提问作者Kap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 12:12:03