The "Hello, World" DirectX 12 sample on GitHub: DirectX-Graphics-Samples is relying on the fact that if you call PeekMessage and there is no other message available, it creates one WM_PAINT message:
MSG msg = {};
while (msg.message != WM_QUIT)
{
// Process any messages in the queue.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
See Microsoft Docs.
Typically game render loops don't rely on the "magic WM_PAINT" behavior, and that what I have in GitHub: directx-vs-templates:
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_game->Tick();
}
}
g_game.reset();
and the only thing WM_PAINT does is clear the screen--with special handling for resizing:
case WM_PAINT:
if (s_in_sizemove && game)
{
game->Tick();
}
else
{
PAINTSTRUCT ps;
(void)BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
Here Tick is a method which does the Update and Render, but depending on the mode of StepTimer it may call Update more than once per frame.
In the end, both Win32 'message pumps' achieve basically the same thing.