Q127192: HOWTO: Draw Controls in an OLE Metafile
Article: Q127192
Product(s): Microsoft C Compiler
Version(s): winnt:2.0,2.1,4.0,4.1,5.0
Operating System(s):
Keyword(s): kbole kbnokeyword kbActiveX kbCOMt kbCtrl kbInplaceAct kbMetafile kbMFC kbVC150 kbVC200
Last Modified: 06-MAY-2001
-------------------------------------------------------------------------------
The information in this article applies to:
- The Microsoft Foundation Classes (MFC), used with:
- Microsoft Visual C++ for Windows, 16-bit edition, versions 1.5, 1.51, 1.52
- Microsoft Visual C++, 32-bit Editions, versions 2.0, 2.1, 4.0, 4.1
- Microsoft Visual C++, 32-bit Enterprise Edition, version 5.0
- Microsoft Visual C++, 32-bit Professional Edition, version 5.0
-------------------------------------------------------------------------------
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 : kbole kbnokeyword kbActiveX kbCOMt kbCtrl kbInplaceAct kbMetafile kbMFC kbVC150 kbVC200 kbVC400 kbVC500 kbGrpDSMFCATL
Technology : kbAudDeveloper kbMFC
Version : winnt:2.0,2.1,4.0,4.1,5.0
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.
Copyright Microsoft Corporation 1986-2002.