We've been using memory device contexts to transfer an existing bitmap to the display. You can also use memory device contexts to draw on the surface of a bitmap. We did this in the GRAFMENU program in Chapter 9, when we used the GetBitmapFont function to make menu items using bitmaps. First, you create a memory device context:
hdcMem = CreateCompatibleDC (hdc) ;
Next, you create a bitmap of the desired size. If you want to create a monochrome bitmap, you can make it compatible with hdcMem:
hBitmap = CreateCompatibleBitmap (hdcMem, xWidth, yHeight) ;
Or to make the bitmap have the same color organization as the video display, you can make the bitmap compatible with hdc:
hBitmap = CreateCompatibleBitmap (hdc, xWidth, yHeight) ;
You can now select the bitmap into the memory device context:
SelectObject (hdcMem, hBitmap) ;
Now you can draw on this memory device context (and by extension, the bitmap) using all the GDI functions we discussed in Chapters 11 and 12 and more that you'll encounter in Chapter 14. When you first create the bitmap, it contains random bits, so you may want to begin by using the PatBlt function with a ROP code of WHITENESS or BLACKNESS to erase the background of the memory device context.
When you're finished drawing on the memory device context, simply delete it:
DeleteDC (hdcMem) ;
Now you're left with a bitmap containing everything you drew on it while it was selected in the memory device context. (We'll go through this process again in the BOUNCE program, shown later in this chapter.)
The SCRAMBLE program, shown in Figure 13-1, uses a memory device context as a temporary holding space for BitBlt operations that swap the contents of two rectangles of the display.
SCRAMBLE.MAK
#------------------------
# SCRAMBLE.MAK make file
#------------------------
scramble.exe : scramble.obj scramble.def
link scramble, /align:16, NUL, /nod slibcew libw, scramble
rc scramble.exe
scramble.obj : scramble.c
cl -c -Gsw -Ow -W2 -Zp scramble.c
SCRAMBLE.C
/*------------------------------------------------
SCRAMBLE.C -- Scramble (and Unscramble) Screen
(c) Charles Petzold, 1990
------------------------------------------------*/
#include <windows.h>
#include <stdlib.h>
#define NUM 200
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static short nKeep [NUM][4] ;
HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL) ;
HDC hdcMem = CreateCompatibleDC (hdc) ;
short cxSize = GetSystemMetrics (SM_CXSCREEN) / 10 ;
short cySize = GetSystemMetrics (SM_CYSCREEN) / 10 ;
HBITMAP hBitmap = CreateCompatibleBitmap (hdc, cxSize, cySize) ;
short i, j, x1, y1, x2, y2 ;
SelectObject (hdcMem, hBitmap) ;
srand (LOWORD (GetCurrentTime ())) ;
for (i = 0 ; i < 2 ; i++)
for (j = 0 ; j < NUM ; j++)
{
if (i == 0)
{
nKeep [j] [0] = x1 = cxSize * (rand () % 10) ;
nKeep [j] [1] = y1 = cySize * (rand () % 10) ;
nKeep [j] [2] = x2 = cxSize * (rand () % 10) ;
nKeep [j] [3] = y2 = cySize * (rand () % 10) ;
}
else
{
x1 = nKeep [NUM - 1 - j] [0] ;
y1 = nKeep [NUM - 1 - j] [1] ;
x2 = nKeep [NUM - 1 - j] [2] ;
y2 = nKeep [NUM - 1 - j] [3] ;
}
BitBlt (hdcMem, 0, 0, cxSize, cySize, hdc, x1, y1, SRCCOPY) ;
BitBlt (hdc, x1, y1, cxSize, cySize, hdc, x2, y2, SRCCOPY) ;
BitBlt (hdc, x2, y2, cxSize, cySize, hdcMem, 0, 0, SRCCOPY) ;
}
return FALSE ;
}
SCRAMBLE.DEF
;-------------------------------------
; SCRAMBLE.DEF module definition file
;-------------------------------------
NAME SCRAMBLE
DESCRIPTION 'Screen Scrambler (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
SCRAMBLE doesn't have a window function. In WinMain, it obtains a device context for the entire screen:
hdc = CreateDC ("DISPLAY", NULL, NULL, NULL) ;
and also a memory device context:
hdcMem = CreateCompatibleDC (hdc) ;
Then it determines the dimensions of the full screen and divides them by 10:
xSize = GetSystemMetrics (SM_CXSCREEN) / 10 ;
ySize = GetSystemMetrics (SM_CYSCREEN) / 10 ;
The program uses these dimensions to create a bitmap:
hBitmap = CreateCompatibleBitmap (hdc, xSize, ySize) ;
and selects it into the memory device context:
SelectObject (hdcMem, hBitmap) ;
Using the normal C rand (”random number generator“) function, SCRAMBLE finds four random values that are multiples of the xSize and ySize values:
x1 = xSize * (rand () % 10) ;
y1 = ySize * (rand () % 10) ;
x2 = xSize * (rand () % 10) ;
y2 = ySize * (rand () % 10) ;
The program swaps two rectangular blocks of the display through the use of three BitBlt functions. The first copies the rectangle beginning at point (x1, y1) into the memory device context:
BitBlt (hdcMem, 0, 0, xSize, ySize, hdc, x1, y1, SRCCOPY) ;
The second copies the rectangle beginning at point (x2, y2) into the location beginning at (x1, y1):
BitBlt (hdc, x1, y1, xSize, ySize, hdc, x2, y2, SRCCOPY) ;
The third copies the rectangle in the memory device context to the area beginning at point (x2, y2):
BitBlt (hdc, x2, y2, xSize, ySize, hdcMem, 0, 0, SRCCOPY) ;
This process effectively swaps the contents of the two rectangles on the display. SCRAMBLE does this 200 times, after which the screen should be thoroughly scrambled. But do not fear, because SCRAMBLE keeps track of this mess and then unscrambles the screen, returning it to normal before exiting.
You can also use memory device contexts to copy the contents of one bitmap to another. For instance, suppose you want to create a bitmap that contains only the upper left quadrant of another bitmap. If the original bitmap has the handle hBitmap, you can copy the dimensions into a structure of type BITMAP:
GetObject (hBitmap, sizeof (BITMAP), (LPSTR) &bm) ;
and create a new uninitialized bitmap of one-quarter the size:
hBitmap2 = CreateBitmap (bm.bmWidth / 2, bm.bmHeight / 2,
bm.bmPlanes, bm.bmBitsPixel, NULL) ;
Now create two memory device contexts and select the original bitmap and the new bitmap into them:
hdcMem1 = CreateCompatibleDC (hdc) ;
hdcMem2 = CreateCompatibleDC (hdc) ;
SelectObject (hdcMem1, hBitmap) ;
SelectObject (hdcMem2, hBitmap2) ;
Finally, copy the upper left quadrant of the first bitmap to the second:
BitBlt (hdcMem2, 0, 0, bm.bmWidth / 2, bm.bmHeight / 2,
hdcMem1, 0, 0, SRCCOPY) ;
You're done except for cleaning up:
DeleteDC (hdcMem1) ;
DeleteDC (hdcMem2) ;