THE MEMORY DEVICE CONTEXT

Two functions—SetDIBitsToDevice and StretchDIBits—allow you to render an array of bits on an output device. However, if you have a handle to a bitmap, there is no function to draw the bitmap on the display surface of a device context. You'll search in vain for a function that looks like this:

DrawBitmap (hdc, hBitmap, xStart, yStart) ; // No such function!!!

This function would copy a bitmap to the device context represented by hdc beginning at the logical point (xStart, yStart). We'll write our own DrawBitmap function later in this chapter. First, however, you need to become familiar with several concepts, starting with the memory device context.

A memory device context is a device context that has a ”display surface“ that exists only in memory. You can create a memory device context using the function:

hdcMem = CreateCompatibleDC (hdc) ;

The hdc handle is a handle to an existing valid device context. The function returns a handle to the memory device context. Upon creation of the memory device context, all the attributes are set to the normal default values. You can do almost anything you want with this memory device context. You can set the attributes to nondefault values, obtain the current settings of the attributes, and select pens, brushes, regions into it. And yes, you can even draw on it. But it doesn't make much sense to do so just yet. Here's why.

When you first create a memory device context, it has a ”display surface“ that contains exactly 1 monochrome pixel. That is a very small display surface. (Don't rely on GetDeviceCaps to tell you this. The HORZSIZE, VERTSIZE, HORZRES, VERTRES, BITSPIXEL, and PLANES values for hdcMem will all be set to the values associated with the original hdc. If GetDeviceCaps really returned the correct values associated with the memory device context when it is first created, then the HORZRES, VERTRES, BITSPIXEL, and PLANES indexes would all return 1.) What you need to do is make the display surface of the memory device context larger. You do this by selecting a bitmap into the device context:

SelectObject (hdcMem, hBitmap) ;

Now the display surface of hdcMem has the same width, height, and color organization as the bitmap referenced by hBitmap. With the default window and viewport origins, the logical point (0, 0) of the memory device context corresponds to the upper left corner of the bitmap.

If the bitmap had some kind of picture on it, then that picture is now part of the memory device context's display surface. Any changes you make to that bitmap (for instance, by using SetBitmapBits to set a different array of bits to the bitmap) are reflected in this display surface. Anything you draw on the memory device context is actually drawn on the bitmap. In short, the bitmap is the display surface of the memory device context.

Earlier I discussed the various functions to create bitmaps. One of them is:

hBitmap = CreateCompatibleBitmap (hdc, xWidth, yHeight) ;

If hdc is the handle to the normal device context for a screen or a printer, then the number of color planes and number of bits per pixel of this bitmap are the same as for the device. However, if hdc is the handle to a memory device context (and no bitmap has yet been selected into the memory device context), then CreateCompatibleBitmap returns a monochrome bitmap that is xWidth pixels wide and yHeight pixels high.

A bitmap is one of six GDI objects. You saw in Chapter 12 how to use SelectObject to select a pen, brush, or region into a device context, and in Chapter 14 you'll learn how to use this function to select a font into a device context. You can use SelectObject to select these four GDI objects into a memory device context also. However, you cannot select a bitmap into a normal device context, only into a memory device context.

When you're finished with the memory device context, you must delete it:

DeleteDC (hdcMem) ;

Well, you may say, this is all very nice, but we haven't yet solved the problem of getting the bitmap on the display. All we've done is select it into a memory device context. Now what? Now we have to learn how to ”blt“ (pronounced ”blit“) the bits from one device context to another.