[PATCH 2/2] user32: Prevent a recursive loop with the activation messages.

Rémi Bernon rbernon at codeweavers.com
Thu Mar 24 16:37:53 CDT 2022


When activating a window and sending activation messages to the window
procedure, Windows avoids a recursive loop by not sending more of these
messages or hooks while it's still activating the window.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/user32/tests/msg.c      |  2 +-
 dlls/win32u/input.c          | 17 ++++++++++++-----
 dlls/win32u/ntuser_private.h |  1 +
 3 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index adb167bdad3..5c7464173c0 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -14827,7 +14827,7 @@ static void test_set_active_window_recursive(HWND hwnd, HWND hwnd2)
 
     flush_sequence();
     SetActiveWindow(hwnd);
-    ok_sequence(RecursiveActivationSeq, "recursive activation", TRUE);
+    ok_sequence(RecursiveActivationSeq, "recursive activation", FALSE);
 
     DestroyWindow(hwnd2);
     DestroyWindow(hwnd);
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index 5cd2cdd0970..29c7e86036c 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -1227,6 +1227,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
         return TRUE;
     }
 
+    if (prev) *prev = previous;
+    if (win_set_flags( hwnd, WIN_IS_ACTIVATING, 0 ) & WIN_IS_ACTIVATING) return TRUE;
+
     /* call CBT hook chain */
     cbt.fMouse     = mouse;
     cbt.hWndActive = previous;
@@ -1246,9 +1249,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
             previous = wine_server_ptr_handle( reply->previous );
     }
     SERVER_END_REQ;
-    if (!ret) return FALSE;
+    if (!ret) goto done;
     if (prev) *prev = previous;
-    if (previous == hwnd) return TRUE;
+    if (previous == hwnd) goto done;
 
     if (hwnd)
     {
@@ -1256,7 +1259,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
         if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ) && user_callbacks)
             user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
                                                   SMTO_ABORTIFHUNG, 2000, NULL );
-        if (!is_window(hwnd)) return FALSE;
+        if (!(ret = is_window( hwnd ))) goto done;
     }
 
     old_thread = previous ? get_window_thread( previous, NULL ) : 0;
@@ -1290,7 +1293,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
 
     if (is_window(hwnd))
     {
-        send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
+        send_message( hwnd, WM_NCACTIVATE,
+                      (hwnd == NtUserGetForegroundWindow()) && !(win_get_flags(previous) & WIN_IS_ACTIVATING),
+                      (LPARAM)previous );
         send_message( hwnd, WM_ACTIVATE,
                       MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ),
                       (LPARAM)previous );
@@ -1313,7 +1318,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
         }
     }
 
-    return TRUE;
+done:
+    win_set_flags( hwnd, 0, WIN_IS_ACTIVATING );
+    return ret;
 }
 
 /**********************************************************************
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index 7c03474286d..5452c722ffa 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -119,6 +119,7 @@ typedef struct tagWND
 #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
 #define WIN_CHILDREN_MOVED        0x0040 /* children may have moved, ignore stored positions */
 #define WIN_HAS_IME_WIN           0x0080 /* the window has been registered with imm32 */
+#define WIN_IS_ACTIVATING         0x0100 /* the window is being activated */
 
 #define WND_OTHER_PROCESS ((WND *)1)  /* returned by WIN_GetPtr on unknown window handles */
 #define WND_DESKTOP       ((WND *)2)  /* returned by WIN_GetPtr on the desktop window */
-- 
2.35.1




More information about the wine-devel mailing list