Windows Metafiles and Embedded Objects

You're going to need a little more Windows theory before you can understand how in-place and embedded components draw in their clients' windows. We've avoided metafiles up to this point because we haven't needed them, but they've always been an integral part of Windows. Think of a metafile as a cassette tape for GDI instructions. To use a cassette, you need a player/recorder, and that's what the metafile device context (DC) is. If you specify a filename when you create the metafile DC, your metafile will be saved on disk; otherwise, it's saved in memory and you get a handle.

In the world of OLE embedding, components create metafiles and containers play them. Here's some component code that creates a metafile containing some text and a rectangle:

CMetaFileDC dcm; // MFC class for metafile DC
VERIFY(dcm.Create());
dcm.SetMapMode(MM_ANISOTROPIC);
dcm.SetWindowOrg(0,0);
dcm.SetWindowExt(5000, -5000);
// drawing code
dcm.Rectangle(CRect(500, -1000, 1500, -2000));
dcm.TextOut(0, 0, m_strText);
HMETAFILE hMF = dcm.Close();
ASSERT(hMF != NULL);

It's possible to create a metafile that uses a fixed mapping mode such as MM_LOENGLISH, but with OLE we'll always use the MM_ANISOTROPIC mode, which is not fixed. The metafile contains a SetWindowExt call to set the x and y extents of the window, and the program that plays the metafile calls SetViewportExt to set the extents of the viewport. Here's some code that you might put inside your container view's OnDraw function:

pDC->SetMapMode(MM_HIMETRIC);
pDC->SetViewportExt(5000, 5000);
pDC->PlayMetafile(hMF);

What's supposed to show up on the screen is a rectangle 1-by-1-cm square because the component assumes the MM_HIMETRIC mapping mode. It will be 1-by-1 cm as long as the viewport extent matches the window extent. If the container sets the viewport extent to (5000, 10000) instead, the rectangle will be stretched vertically but the text will be the same size because it's drawn with the nonscalable system font. If the container decided to use a mapping mode other than MM_HIMETRIC, it could adjust the viewport extent to retain the 1-by-1-cm size.

To reiterate, the component sets the window extent to the assumed size of the viewable area and draws inside that box. If the component uses a negative y extent, the drawing code works just as it does in MM_HIMETRIC mapping mode. The container somehow gets the component's extent size and attempts to draw the metafile in an area with those HIMETRIC dimensions.

Why are we bothering with metafiles? Because the container needs to draw something in the component's rectangle, even if the component program isn't running. The component creates the metafile and hands it off in a data object to the in-process OLE handler module on the container side of the Remote Procedure Call (RPC) link. The handler then caches the metafile and plays it on demand and also transfers it to and from the container's storage. When a component is in-place active, however, its view code is drawing directly in a window that's managed by the container.