I have window with Button
control, to drawing I use Direct2D
, important WindowProc
fragments:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
case WM_CREATE:
HWND button = CreateWindowExW(0, L"button", L"Send", WS_CHILD | WS_VISIBLE, 10, 10, 200, 100, hWnd, CONTROL_ID, desc->hInstance, 0);
break;
case WM_PAINT:
render_target->BeginDraw();
... rendering stuff ...
HRESULT result = render_target->EndDraw();
// Validate region:
ValidateRgn(hWnd, nullptr); // validate entire client area
break;
...
}
This code doesn't quite work, my child Button
was not painted. I suppose it doesn't receive WM_PAINT
message because I validated entire window, hence Window don't ask to repaint the same pixels twice.
So I take that into consideration, and exclude Button
region from validation:
// Validate region:
HRGN update = CreateRectRgn(0, 0, 0, 0);
HRGN button = CreateRectRgn(10, 10, 210, 110);
GetUpdateRgn(hWnd, update, false); // get update rect
CombineRgn(update, update, tab, RGN_DIFF); // exclude button region
ValidateRgn(hWnd, update); // validate window client area (excluding button) to stop receiving WM_MESSAGE
Now Button
still is not painted, what's more I receive WM_PAINT
in infinite loop, with update region equal Rgn(10, 10, 210, 110)
. I expected that after WM_PAINT
in WindowProc
, child Button
should received it and there missing update region will be validated.
Everything works if I wrap WM_PAINT
message in BeginPaint(hWnd, nullptr)
EndPaint(hWnd, nullptr)
:
case WM_PAINT:
::log << "WINDOW_PAINT_START" << std::endl;
BeginPaint(hWnd, nullptr); // use BeginPaint from GDI
render_target->BeginDraw();
... rendering stuff ...
HRESULT result = render_target->EndDraw();
// Validate region code is not needed anymore because BeginPaint take care of that.
EndPaint(hWnd, nullptr);
::log << "WINDOW_PAINT_END" << std::endl;
break;
It seems to BeginPaint()
validate update region and trigger WM_PAINT
for children windows. It should be called in response to WM_PAINT
even if you don't use GDI
and it's PAINTSTRUCT->HDC
.
But if BeginPaint()
indeed trigger WM_PAINT
for children windows then my log calling order should looks like WINDOW_PAINT_START -> BUTTON_PAINT_START -> BUTTON_PAINT_END -> WINDOW_PAINT_END
, in fact looks like WINDOW_PAINT_START -> WINDOW_PAINT_END -> BUTTON_PAINT_START -> BUTTON_PAINT_END
. So WM_PAINT
for Button
is delayed until WinProc
returns from it's WM_PAINT
: hence trigger happen outside, hence children drawing happend after main window paint which is in compliance with MSDN.
So exactly in which moment WM_PAINT
to children windows is dispatched?