Microsoft KB Archive/105444

From BetaArchive Wiki

Implementing Print Margins in a Windows MFC Application


The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), included with:
    • Microsoft Visual C++, versions 1.0, 1.5


To implement accurate print margins, applications should use the GETPHYSPAGESIZE and GETPRINTINGOFFSET printer escapes, as well as CDC::GetDeviceCaps() with LOGPIXELSX/LOGPIXELSY, HORZRES/VERTRES, and/or HORZSIZE/VERTSIZE.


For a detailed description of the above functions, see the Microsoft Knowledge Base article Q11863 "Printer Page Area in Windows."

The following example demonstrates one method to implement print margins in the SuperPad Microsoft Foundation Class (MFC) Libraries sample. Because SuperPad already uses the m_rectDraw member of CPrintInfo, the method demonstrated here modifies this rectangle during OnPrint(). Note that modifying m_rectDraw during OnBeginPrinting() or OnPrepareDC() has no effect because CView::OnFilePrint() initializes m_rectDraw immediately after calling OnPrepareDC().

  1. Use App Studio and ClassWizard to add controls and corresponding variables for the margin settings to the Page Setup dialog box in SuperPad (CPageSetupDlg). CPageSetupDlg is not related to the common dialog CPrintDialog, but is a CDialog used by SuperPad to set the header and footer strings that SuperPad adds to each page when it prints, and is an intuitive place to add controls for setting margins. The units used for input should be device-independent units, such as inches or centimeters.

    The code below assumes that CPageSetupDlg has a CRect member named m_rMargin that contains the current margin values in MM_HIMETRIC units. To use this code, add m_rMargin to CPageSetupDlg and modify CPageSetupDlg::DoDataExchange to convert new margin values to MM_HIMETRIC units; save them in m_rMargin.
  2. Add a CRect member named m_rectMargins to the CPadView class and add the following function to CPadView. This function converts the device-independent margins in CPageSetupDlg::m_rMargin into device-dependent values for the current printer. The printing rectangle (CPrintInfo::m_rectDraw) representing the printable area of the page is then reduced by these amounts in OnPrint().

    Sample Code

       void CPadView::CalculateMargins(CDC* pDC)
       POINT pt;
       // Start by getting the dimensions of the unprintable part of the
       // page (in device units). GETPRINTINGOFFSET will tell us the left
       // and upper unprintable area.
       pDC->Escape(GETPRINTINGOFFSET, 0, NULL, &pt);
       m_rectMargins.left = pt.x;  = pt.y;
       // To get the right and lower unprintable area, we need to take
       // the entire width and height of the paper (GETPHYSPAGESIZE) and
       // subtract everything else.
       pDC->Escape(GETPHYSPAGESIZE, 0, NULL, &pt);
       m_rectMargins.right  = pt.x                     // total paper width
                              - pDC->GetDeviceCaps(HORZRES) // printable width
                              - m_rectMargins.left;   // left unprtable margin
       m_rectMargins.bottom = pt.y                     // total paper height
                              - pDC->GetDeviceCaps(VERTRES) // printable ht
                              -;    // rt unprtable margin
       // At this point, m_rectMargins contains the widths of the
       // unprintable regions on all four sides of the page in device units.
       // Convert the Hi-Metric margin values from the Page Setup dialog
       // to device units and subtract the unprintable part we just
       // calculated. Save the results back in m_rectMargins.
       // (2540 == # of Hi-Metric units in an inch)
       pt.x = pDC->GetDeviceCaps(LOGPIXELSX);    // dpi in X direction
       pt.y = pDC->GetDeviceCaps(LOGPIXELSY);    // dpi in Y direction
       m_rectMargins.left   = MulDiv(dlgPageSetup.m_rMargin.left, pt.x, 2540)
                             - m_rectMargins.left;    = MulDiv(, pt.y, 2540)
       m_rectMargins.right  = MulDiv(dlgPageSetup.m_rMargin.right, pt.x, 2540)
                             - m_rectMargins.right;
       m_rectMargins.bottom = MulDiv(dlgPageSetup.m_rMargin.bottom, pt.y,2540)
                             - m_rectMargins.bottom;
       // m_rectMargins now contains the values used to shrink the printable
       // area of the page. Could check m_rectMargins here for negative values
       // to prevent setting margins outside the printable area of the page.
       // Convert to logical units and we're done!
  3. Call CalculateMargins() in CPadView::OnBeginPrinting() or another appropriate place. If a mapping mode other than MM_TEXT were used, it would be necessary to call CalculateMargins() after the mapping mode is set (normally in OnPrepareDC).

       void CPadView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
           CEditView::OnBeginPrinting(pDC, pInfo);
           CalculateMargins(pDC);  // add this line
           // etc.
  4. Finally, in CPadView::OnPrint(), add the following four lines to shrink the printing rectangle according to the values calculated previously. m_rectDraw is initialized to the entire printable area (in logical units) for every page.

       CRect rectPage = pInfo->m_rectDraw;     // existing code in OnPrint
       rectPage.left   += m_rectMargins.left;  // add these four lines    +=;
       rectPage.right  -= m_rectMargins.right;
       rectPage.bottom -= m_rectMargins.bottom;
       if (!strHeader.IsEmpty())               // existing code

SuperPad automatically adjusts its printed output to be contained in the rectPage rectangle.

Additional query words: kbinf 1.00 1.50 2.00 2.50 no32bit noupdate

Keywords : kb16bitonly kbMFC kbPrinting kbVC
Issue type :
Technology : kbAudDeveloper kbMFC

Last Reviewed: May 8, 2001
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.