3.1.2 Processing a WM_PAINT Message

Windows posts a WM_PAINT message when the user has changed the window—for example, by closing a window that covered part of another window. Because a window shares the screen with other windows, anything the user does in one window can affect the content and appearance of another window. However, an application can do nothing about the change until it receives the WM_PAINT message.

Windows posts a WM_PAINT message by making it the last message in the application queue. This means any input is processed before the WM_PAINT message. In fact, the GetMessage function also retrieves any input generated after the WM_PAINT message is posted. That is, GetMessage retrieves the WM_PAINT message from the queue only when there are no other messages. This enables the application to carry out any operations that might affect the appearance of the window. In general, to avoid flicker and other distracting effects, your application should perform output operations as infrequently as possible. Windows helps ensure this by holding the WM_PAINT message until it is the last message in the queue.

The following example shows how to process a WM_PAINT message:

PAINTSTRUCT ps;
    .
    .
    .

case WM_PAINT:
    hDC = BeginPaint(hWnd, &ps);

    /* Output operations */

    EndPaint(hWnd, &ps);
    break;

The BeginPaint and EndPaint functions are required. The BeginPaint function fills the PAINTSTRUCT structure, ps, with information about the paint request, such as the part of the client area that needs redrawing. The function then returns a handle to the device context. Your application can use this handle in any GDI output functions. The EndPaint function ends the paint request and releases the device context.

You should not use the GetDC and ReleaseDC functions in place of the BeginPaint and EndPaint functions. BeginPaint and EndPaint perform special tasks, such as validating the client area and sending the WM_ERASEBKGND message, that ensure the paint request is processed properly. If you use GetDC and ReleaseDC, you must follow the call to ReleaseDC with a call to the ValidateRect function. If you do not call ValidateRect, the WM_PAINT message is not removed from the message queue and your application will receive it again.