HOWTO: Draw Controls in an OLE Metafile

Last reviewed: February 17, 1998
Article ID: Q127192
The information in this article applies to:
  • The Microsoft Foundation Classes (MFC) included with:

        - Microsoft Visual C++ for Windows, versions 1.5, 1.51, 1.52
        - Microsoft Visual C++, 32-bit Edition, versions 2.0, 2.1,
          4.0, 4.1, 5,0
          on the following platform: x86
    

SUMMARY

You can use controls, either directly on a CView or from a dialog template on a CFormView, in an OLE enabled MFC application. However, when the item is embedded but not active, the controls on these views will not be drawn to the Windows metafile supplied to the COleServerItem::OnDraw() function. In this case, you must "draw" the controls manually into the metafile. This article shows you how.

MORE INFORMATION

The simplest way to get controls to "draw" in a metafile is to use the same method the VIEWEX sample uses to draw its CInputView to a printer device context. VIEWEX's OnPrint routine draws each control as a rectangle, circle, text, and so on. Override the COleServerItem::OnDraw() function and insert your code into it. As an example, use the COleServerItem::OnDraw() function listed in this article; it shows both the VIEWEX code to insert in the OnDraw member function and the helper function PaintChildWindows() that actually does the painting of each control.

Sample Code

/* Compile options needed: Standard
*/

void CMyServerItem::OnDraw(CDC* pDC) // pDC is actually a metafile
{
    //BLOCK: Set up scale mode
    {
        CClientDC dcScreen(NULL);
        pDC->SetMapMode(MM_ANISOTROPIC);
        // map 1 screen logical inch to 1 printer (/output) logical inch
        pDC->SetWindowExt(dcScreen.GetDeviceCaps(LOGPIXELSX),
                dcScreen.GetDeviceCaps(LOGPIXELSX));
        pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),
                pDC->GetDeviceCaps(LOGPIXELSX));
    }
    // we must also offset the window positions relative to the scroll
    // offset

    // We cheat here since some controls do not paint if they are
    // invisible, so we temporary make set the appropriate visible bits
    // during preview mode so the controls think they are visible even
    // though they aren't.

    HWND hWndCheatVisible = NULL;
    if (!IsWindowVisible())
    {
        // walk up to the top until we find the invisible window
        for (HWND hWnd = m_hWnd;
            hWnd != NULL; hWnd = ::GetParent(hWnd))
        {
            ASSERT(hWnd != NULL);
            DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
            if ((dwStyle & WS_VISIBLE) == 0)
            {
                ::SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_VISIBLE);
                hWndCheatVisible = hWnd;
                break;
            }
        }
        ASSERT(hWndCheatVisible != NULL);
    }

    CPen pen(PS_SOLID, 1, RGB(0,0,0));  // solid black pen
    CPen* pOldPen = pDC->SelectObject(&pen);

    ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
    CRect pRect = new CRect(-50,-50,600,600);

    PaintChildWindows(m_hWnd, pDC, GetDeviceScrollPosition());
    ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
    pDC->SelectObject(pOldPen);

    if (hWndCheatVisible != NULL)
        ::SetWindowLong(hWndCheatVisible, GWL_STYLE,
            ::GetWindowLong(hWndCheatVisible, GWL_STYLE) &~ WS_VISIBLE);
}

void CMyServerItem::PaintChildWindows(HWND hWndParent,
                                      CDC* pDC, CPoint ptOffset)
{
    for (HWND hWndChild = ::GetTopWindow(hWndParent);
        hWndChild != NULL;
        hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
    {
        CRect rect;
        ::GetWindowRect(hWndChild, rect);  // wnd rect in screen coords
        ScreenToClient(&rect);             // relative to this view

        HDC hdcOut = pDC->m_hDC;
#ifdef _DEBUG
        CPoint pt = pDC->GetWindowOrg();
        ASSERT(pt.x == 0 && pt.y == 0);
#endif

        DWORD dwStyle = ::GetWindowLong(hWndChild, GWL_STYLE);
        if (dwStyle & (WS_HSCROLL|WS_VSCROLL))
        {
            TRACE("Warning: printing control with scrollbars not
 supported\n");
        }
        if (dwStyle & WS_BORDER)
        {
            // the only case we special case - manually drawn border
            ::Rectangle(hdcOut, rect.left, rect.top, rect.right,
                        rect.bottom);
            rect.InflateRect(-1,-1);        // 1 logical pixel
        }

        pDC->SaveDC();
        {
            CPoint pt(ptOffset.x + rect.left, ptOffset.y + rect.top);
            pDC->LPtoDP(&pt);
            pDC->OffsetViewportOrg(pt.x, pt.y);
                // set the viewport origin so that the window origin
                //  can be changed by the control

            // draw it using a non-virtual HDC
            ::SendMessage(hWndChild, WM_PAINT, (WPARAM)hdcOut, 0L);
        }
        pDC->RestoreDC(-1);

        if (::GetTopWindow(hWndChild) != NULL)
            PaintChildWindows(hWndChild, pDC, ptOffset);
    }
}


Additional query words: mfc ole inplace embed
Keywords : MfcOLE
Technology : kbole kbMfc
Version : WINDOWS:1.5,1.51,1.52,2.0,2.1,4.0,5.0
Platform : NT WINDOWS
Hardware : x86
Issue type : kbhowto


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: February 17, 1998
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.