From cf470941031e6c411aa051e17e348b2eb292aeba Mon Sep 17 00:00:00 2001 From: Ahmed Arif Date: Mon, 29 Jun 2026 21:20:26 +0200 Subject: [PATCH] [NTUSER] Preserve WM_QUIT in move/size modal loop (#9087) Dragging the first-boot install/status window could make setup stall, and the shell never started after that. The problem is that the move/size modal loop can remove a posted `WM_QUIT` while setup is tearing the thread down. That quit message then does not reach the outer `GetMessage()` loop, so the setup thread keeps waiting instead of exiting. This fix keeps the `WM_QUIT` message alive by re-posting it and leaving the move/size loop. See also: https://devblogs.microsoft.com/oldnewthing/20050222-00/?p=36393 ## How to test Boot to first-boot setup, drag the install/status window while it is finishing, and check that setup continues and Explorer starts instead of hanging. --- win32ss/user/ntuser/nonclient.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/win32ss/user/ntuser/nonclient.c b/win32ss/user/ntuser/nonclient.c index 60128768435..1df97d684fa 100644 --- a/win32ss/user/ntuser/nonclient.c +++ b/win32ss/user/ntuser/nonclient.c @@ -187,6 +187,11 @@ DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint) while (!hittest) { if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) return 0; + if (msg.message == WM_QUIT) + { + MsqPostQuitMessage(pti, (ULONG)msg.wParam); + return 0; + } if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue; switch(msg.message) @@ -408,6 +413,11 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) int dx = 0, dy = 0; if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break; + if (msg.message == WM_QUIT) + { + MsqPostQuitMessage(pti, (ULONG)msg.wParam); + break; + } if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue; if (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE))