Added user32-recursive-activation patchset

This commit is contained in:
Alistair Leslie-Hughes 2019-08-05 10:27:34 +10:00
parent 9917fb4559
commit ad822b6405
4 changed files with 305 additions and 0 deletions

View File

@ -303,6 +303,7 @@ patch_enable_all ()
enable_user32_ScrollWindowEx="$1"
enable_user32_ShowWindow="$1"
enable_user32_msgbox_Support_WM_COPY_mesg="$1"
enable_user32_recursive_activation="$1"
enable_uxtheme_CloseThemeClass="$1"
enable_uxtheme_GTK_Theming="$1"
enable_version_VerQueryValue="$1"
@ -1039,6 +1040,9 @@ patch_enable ()
user32-msgbox-Support-WM_COPY-mesg)
enable_user32_msgbox_Support_WM_COPY_mesg="$2"
;;
user32-recursive-activation)
enable_user32_recursive_activation="$2"
;;
uxtheme-CloseThemeClass)
enable_uxtheme_CloseThemeClass="$2"
;;
@ -6427,6 +6431,23 @@ if test "$enable_user32_msgbox_Support_WM_COPY_mesg" -eq 1; then
) >> "$patchlist"
fi
# Patchset user32-recursive-activation
# |
# | This patchset fixes the following Wine bugs:
# | * [#46274] user32: Prevent a recursive loop with the activation messages.
# |
# | Modified files:
# | * dlls/user32/focus.c, dlls/user32/tests/msg.c, dlls/user32/win.h
# |
if test "$enable_user32_recursive_activation" -eq 1; then
patch_apply user32-recursive-activation/0001-user32-focus-Prevent-a-recursive-loop-with-the-activ.patch
patch_apply user32-recursive-activation/0002-user32-tests-Test-a-recursive-activation-loop-on-WM_.patch
(
printf '%s\n' '+ { "Gabriel Ivăncescu", "user32/focus: Prevent a recursive loop with the activation messages.", 1 },';
printf '%s\n' '+ { "Gabriel Ivăncescu", "user32/tests: Test a recursive activation loop on WM_ACTIVATE.", 1 },';
) >> "$patchlist"
fi
# Patchset uxtheme-CloseThemeClass
# |
# | This patchset fixes the following Wine bugs:

View File

@ -0,0 +1,142 @@
From b41d5d29f777dccdd43f09270858f2ca032db00d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= <gabrielopcode@gmail.com>
Date: Mon, 22 Jul 2019 15:29:25 +0300
Subject: [PATCH 1/2] user32/focus: Prevent a recursive loop with the
activation messages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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. Some applications
actually depend on this behavior, so it is needed.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
---
dlls/user32/focus.c | 44 +++++++++++++++++++++++++++--------------
dlls/user32/tests/msg.c | 2 +-
dlls/user32/win.h | 1 +
3 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c
index f1c883167e..0d32d008a7 100644
--- a/dlls/user32/focus.c
+++ b/dlls/user32/focus.c
@@ -78,7 +78,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
{
HWND previous = GetActiveWindow();
BOOL ret;
- DWORD old_thread, new_thread;
+ DWORD winflags, old_thread, new_thread;
CBTACTIVATESTRUCT cbt;
if (previous == hwnd)
@@ -87,16 +87,24 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
return TRUE;
}
- /* call CBT hook chain */
- cbt.fMouse = mouse;
- cbt.hWndActive = previous;
- if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
-
- if (IsWindow(previous))
+ /* Prevent a recursive activation loop with the activation messages */
+ winflags = win_set_flags(hwnd, WIN_IS_IN_ACTIVATION, 0);
+ if (!(winflags & WIN_IS_IN_ACTIVATION))
{
- SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
- SendMessageW( previous, WM_ACTIVATE,
- MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
+ ret = FALSE;
+
+ /* call CBT hook chain */
+ cbt.fMouse = mouse;
+ cbt.hWndActive = previous;
+ if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE ))
+ goto clear_flags;
+
+ if (IsWindow(previous))
+ {
+ SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
+ SendMessageW( previous, WM_ACTIVATE,
+ MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
+ }
}
SERVER_START_REQ( set_active_window )
@@ -106,9 +114,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 clear_flags;
if (prev) *prev = previous;
- if (previous == hwnd) return TRUE;
+ if (previous == hwnd) goto clear_flags;
if (hwnd)
{
@@ -116,7 +124,11 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
SMTO_ABORTIFHUNG, 2000, NULL );
- if (!IsWindow(hwnd)) return FALSE;
+ if (!IsWindow(hwnd))
+ {
+ ret = FALSE;
+ goto clear_flags;
+ }
}
old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
@@ -148,7 +160,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
}
}
- if (IsWindow(hwnd))
+ if (!(winflags & WIN_IS_IN_ACTIVATION) && IsWindow(hwnd))
{
SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
SendMessageW( hwnd, WM_ACTIVATE,
@@ -173,7 +185,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
}
}
- return TRUE;
+clear_flags:
+ win_set_flags(hwnd, 0, WIN_IS_IN_ACTIVATION);
+ return ret;
}
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index a5bc1c5518..64f7eeecf3 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -5142,7 +5142,7 @@ static void test_messages(void)
ShowWindow(hwnd, SW_MINIMIZE);
flush_events();
- ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
+ ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
flush_sequence();
if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 1f51fd6331..a64cc66be5 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -79,6 +79,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_IN_ACTIVATION 0x0100 /* the window is in an activation process */
/* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;
--
2.17.1

View File

@ -0,0 +1,140 @@
From 064570eb530a73e822bf19ccb9bc31cd3654c504 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= <gabrielopcode@gmail.com>
Date: Mon, 22 Jul 2019 15:29:26 +0300
Subject: [PATCH 2/2] user32/tests: Test a recursive activation loop on
WM_ACTIVATE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Windows only sends the activation messages and hooks once, until the
SetActiveWindow completes for that window.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
---
dlls/user32/tests/msg.c | 81 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 64f7eeecf3..191e7bfffb 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -4772,6 +4772,39 @@ static void test_showwindow(void)
flush_sequence();
}
+static void test_recursive_activation(void)
+{
+ static const struct message seq[] =
+ {
+ { HCBT_ACTIVATE, hook },
+ { WM_NCACTIVATE, sent|wparam, TRUE },
+ { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
+ { HCBT_ACTIVATE, hook },
+ { WM_NCACTIVATE, sent|wparam, FALSE },
+ { WM_ACTIVATE, sent|wparam, WA_INACTIVE },
+ { WM_SETFOCUS, sent|optional },
+ { 0 }
+ };
+ HWND hwnd, recursive;
+
+ hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok(hwnd != 0, "Failed to create simple window\n");
+
+ recursive = CreateWindowExA(0, "RecursiveActivationClass", NULL, WS_OVERLAPPED|WS_VISIBLE,
+ 10, 10, 50, 50, hwnd, 0, 0, NULL);
+ ok(recursive != 0, "Failed to create recursive activation window\n");
+ SetActiveWindow(hwnd);
+
+ flush_sequence();
+ SetActiveWindow(recursive);
+ ok_sequence(seq, "Recursive Activation", FALSE);
+
+ DestroyWindow(recursive);
+ DestroyWindow(hwnd);
+ flush_sequence();
+}
+
static void test_sys_menu(void)
{
HWND hwnd;
@@ -9699,6 +9732,48 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP
return ret;
}
+static LRESULT WINAPI recursive_activation_wndprocA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static LONG defwndproc_counter = 0;
+ struct recvd_message msg;
+ LRESULT ret;
+
+ switch (message)
+ {
+ /* log only specific messages we are interested in */
+ case WM_NCACTIVATE:
+ case WM_ACTIVATE:
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ break;
+ default:
+ return DefWindowProcA(hwnd, message, wParam, lParam);
+ }
+
+ msg.hwnd = hwnd;
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.descr = "recursive_activation";
+ add_message(&msg);
+
+ /* recursively activate ourselves by first losing activation and changing it back */
+ if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE)
+ {
+ SetActiveWindow((HWND)lParam);
+ SetActiveWindow(hwnd);
+ return 0;
+ }
+
+ defwndproc_counter++;
+ ret = DefWindowProcA(hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
@@ -9796,6 +9871,10 @@ static BOOL RegisterWindowClasses(void)
cls.lpszClassName = "ShowWindowClass";
if(!RegisterClassA(&cls)) return FALSE;
+ cls.lpfnWndProc = recursive_activation_wndprocA;
+ cls.lpszClassName = "RecursiveActivationClass";
+ if(!RegisterClassA(&cls)) return FALSE;
+
cls.lpfnWndProc = PopupMsgCheckProcA;
cls.lpszClassName = "TestPopupClass";
if(!RegisterClassA(&cls)) return FALSE;
@@ -9851,6 +9930,7 @@ static BOOL is_our_logged_class(HWND hwnd)
{
if (!lstrcmpiA(buf, "TestWindowClass") ||
!lstrcmpiA(buf, "ShowWindowClass") ||
+ !lstrcmpiA(buf, "RecursiveActivationClass") ||
!lstrcmpiA(buf, "TestParentClass") ||
!lstrcmpiA(buf, "TestPopupClass") ||
!lstrcmpiA(buf, "SimpleWindowClass") ||
@@ -17756,6 +17836,7 @@ START_TEST(msg)
test_messages();
test_setwindowpos();
test_showwindow();
+ test_recursive_activation();
invisible_parent_tests();
test_mdi_messages();
test_button_messages();
--
2.17.1

View File

@ -0,0 +1,2 @@
Fixes: [46274] user32: Prevent a recursive loop with the activation messages.