3
votes

I'm new to windows programming and I have a question about painting the windows, specifically about BeginPaint function

When I was reading about it on MSDN it says that

Start the painting operation by calling the BeginPaint function. This function fills in the PAINTSTRUCT structure with information on the repaint request. The current update region is given in the rcPaint member of PAINTSTRUCT.

my question is when I handle the WM_PAINT message in my wndproc and start by calling BeginPaint function, I didn't provide this function with any data about the particular message I received or the update region that needs to be painted, So how does this function fill the PAINTSTRUCT including the invalid rect "rcPaint member" ?!

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        // All painting occurs here, between BeginPaint and EndPaint.
        EndPaint(hwnd, &ps);
    }

and when I referenced BeginPaint function on MSDN, It says

An application should not call BeginPaint except in response to a WM_PAINT message

My guess is may be this function gets this information internally from Windows by requesting for this information and the last WM_PAINT message sent to the window that I passed it's handle "`hwnd'" as the first parameter to the function. Is that correct ?

thanks in advance.

2

2 Answers

6
votes

I doubt this is documented anywhere as it's an implementation detail that doesn't concern programmers, but I'm pretty sure the update region is an internal data structure stored along with the HWND. You can tell because there are several functions that operate on the update region based only on the HWND: [In]ValidateRect, [In]ValidateRgn, GetUpdateRgn, BeginPaint, etc.

5
votes

Windows maintains an internal data structure for every window, which holds its invalid region. The RECT member of the PAINTSTRUCT structure is set to equal this rectangle (the smallest rectangle containing the invalid region). As user1610015 already pointed out, this is not something that concern programmers typically.

When you call

hdc = BeginPaint(hwnd, &ps);

the RECT structure of the PAINTSTRUCTURE struct is updated with the invalid rectangle.

My guess is may be this function gets this information internally from Windows by requesting for this information and the last WM_PAINT message sent to the window that I passed it's handle "`hwnd'" as the first parameter to the function. Is that correct ?

Windows does not place multiple WM_PAINT messages on the message queue. Instead it keeps updating the window update region. For example, if you have already have a WM_PAINT message in the message queue, and before this message is removed from the queue by the call

GetMessage(&msg, NULL, 0, 0)

, you validate/alter the update region (via for example ValidateRect) then Windows updates the internal update region is holds for the window. If your call to ValidateRect validates the entire invalid region then the WM_PAINT message is removed from the message queue, without ever being processed.

Moreover, when you call

hdc = BeginPaint(hwnd, &ps);

the Device Context (DC) you obtain contains a default rectangular clipping region which equals the invalid rectangle (the same rectangle that rcPaint in PAINSTRUCT is set to equal). You cannot draw outside the clipping region. You can for example offset the clipping region with

// This does not change the update region for the window
// This changes the clipping region associated with the DC hdc
OffsetClipRgn(hdc, xOffset, yOffset);

To summarize, the invalid region is not necessarily equal to the clipping region (but usually it is since BeginPaint accomplishes this). The presence of a non-empty invalid/update region for the window (which windows handles internally) is what causes a WM_PAINT to be placed in the message queue.