This is required to avoid silencing (potentially fatal) exceptions from timer procedures.
-- v3: win32u: Ignore unhandled info index in NtUserSetObjectInformation. win32u/tests: Add tests for NtUserSetObjectInformation. user32: Implement UOI_TIMERPROC_EXCEPTION_SUPPRESSION. user32/tests: Add tests for UOI_TIMERPROC_EXCEPTION_SUPPRESSION.
From: Jinoh Kang jinoh.kang.kr@gmail.com
Commit e445303ab45 (user32/tests: Make a few more messages optional., 2014-03-20) modified test_unicode_wm_char so that it skips non-essential messages (e.g. WM_DWMNCRENDERINGCHANGED) from GetMessageW.
Extend this for messages from GetMessageA as well.
Also, handle the case where no messages other than WM_QUIT are received at all.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/user32/tests/msg.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 23957a7adf8..68782658724 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -16172,6 +16172,16 @@ static void test_dbcs_wm_char(void) DestroyWindow(hwnd2); }
+static BOOL get_next_msg( BOOL (*WINAPI getmessage)(MSG *, HWND, UINT, UINT), + MSG *msg, HWND hwnd ) +{ + while ((*getmessage)( msg, hwnd, 0, 0 )) + { + if (!ignore_message( msg->message )) return TRUE; + } + return FALSE; +} + static void test_unicode_wm_char(void) { HWND hwnd; @@ -16202,11 +16212,7 @@ static void test_unicode_wm_char(void)
PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
- while (GetMessageW( &msg, hwnd, 0, 0 )) - { - if (!ignore_message( msg.message )) break; - } - + ok( get_next_msg( GetMessageW, &msg, hwnd ), "expected a recongized message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); ok( msg.wParam == 0x3b1, "bad wparam %Ix\n", msg.wParam ); @@ -16226,7 +16232,7 @@ static void test_unicode_wm_char(void) /* greek alpha -> 'a' in cp1252 */ PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
- ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" ); + ok( get_next_msg( GetMessageA, &msg, hwnd ), "expected a recognized message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); ok( msg.wParam == 0x61, "bad wparam %Ix\n", msg.wParam ); @@ -16247,7 +16253,7 @@ static void test_unicode_wm_char(void) /* greek alpha -> 0xe1 in cp1253 */ PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
- ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" ); + ok( get_next_msg( GetMessageA, &msg, hwnd ), "expected a recognized message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); ok( msg.wParam == 0xe1, "bad wparam %Ix\n", msg.wParam );
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- include/winuser.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/winuser.h b/include/winuser.h index 453f561e62f..666deeb6cbe 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -99,6 +99,7 @@ typedef void* HPOWERNOTIFY; #define UOI_NAME 2 #define UOI_TYPE 3 #define UOI_USER_SID 4 +#define UOI_TIMERPROC_EXCEPTION_SUPPRESSION 7
#define WSF_VISIBLE 1 #define DF_ALLOWOTHERACCOUNTHOOK 1
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/user32/tests/msg.c | 104 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 68782658724..960c57c9076 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -11405,11 +11405,36 @@ static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR count++; }
+enum timer_exception_phase { + TIMER_EXCEPTION_INITIAL, + TIMER_EXCEPTION_RAISED, + TIMER_EXCEPTION_CONTINUE, + TIMER_EXCEPTION_CONTINUE_OK, +}; + static DWORD exception; +static enum timer_exception_phase timer_exc_phase; +static BOOL tproc_exc_no_suppress; static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + if (tproc_exc_no_suppress) + { + BOOL ret, value; + + value = FALSE; + ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, + &value, sizeof(value)); + todo_wine + ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); + tproc_exc_no_suppress = FALSE; + } + count++; + timer_exc_phase = TIMER_EXCEPTION_RAISED; RaiseException(exception, 0, 0, NULL); + ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE, + "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE, timer_exc_phase); + timer_exc_phase = TIMER_EXCEPTION_CONTINUE_OK; }
static DWORD WINAPI timer_thread_proc(LPVOID x) @@ -11570,10 +11595,42 @@ static void test_timers_no_wnd(void) while (i > 0) KillTimer(NULL, ids[--i]); }
+static LONG CALLBACK timer_exception_handler(EXCEPTION_POINTERS *eptr) +{ + if (timer_exc_phase == TIMER_EXCEPTION_RAISED && + eptr->ExceptionRecord->ExceptionCode == exception && + eptr->ExceptionRecord->ExceptionFlags == 0 && + eptr->ExceptionRecord->NumberParameters == 0) + { + if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) + { +#if defined(__i386__) + if ((ULONG_PTR)eptr->ExceptionRecord->ExceptionAddress == eptr->ContextRecord->Eip + 1) + eptr->ContextRecord->Eip++; /* cancel EIP rewinding */ +#elif defined(__x86_64__) + if ((ULONG_PTR)eptr->ExceptionRecord->ExceptionAddress == eptr->ContextRecord->Rip + 1) + eptr->ContextRecord->Rip++; /* cancel RIP rewinding */ +#endif + } + timer_exc_phase = TIMER_EXCEPTION_CONTINUE; + return EXCEPTION_CONTINUE_EXECUTION; + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +static void dispatch_message_ansi_handle_exception(const MSG *msg, PVECTORED_EXCEPTION_HANDLER handler) +{ + void *cookie = AddVectoredExceptionHandler(TRUE, handler); + DispatchMessageA(msg); + RemoveVectoredExceptionHandler(cookie); +} + static void test_timers_exception(DWORD code) { UINT_PTR id; MSG msg; + BOOL ret, value;
exception = code; id = SetTimer(NULL, 0, 1000, callback_exception); @@ -11585,8 +11642,55 @@ static void test_timers_exception(DWORD code) msg.lParam = (LPARAM)callback_exception;
count = 0; + timer_exc_phase = TIMER_EXCEPTION_INITIAL; DispatchMessageA(&msg); ok(count == 1, "did not get one count as expected (%i).\n", count); + ok(timer_exc_phase == TIMER_EXCEPTION_RAISED, + "expected phase %d, got %d\n", TIMER_EXCEPTION_RAISED, timer_exc_phase); + + value = FALSE; + ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, + &value, sizeof(value)); + if (!ret && GetLastError() == ERROR_INVALID_FUNCTION) + { + win_skip("UOI_TIMERPROC_EXCEPTION_SUPPRESSION not supported on this platform\n"); + } + else + { + todo_wine + ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); + + count = 0; + timer_exc_phase = TIMER_EXCEPTION_INITIAL; + dispatch_message_ansi_handle_exception(&msg, timer_exception_handler); + ok(count == 1, "expected count to be 1, got %d\n", count); + todo_wine + ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK || + broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */, + "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase); + + value = TRUE; + ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, + &value, sizeof(value)); + todo_wine + ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); + + tproc_exc_no_suppress = TRUE; + count = 0; + timer_exc_phase = TIMER_EXCEPTION_INITIAL; + dispatch_message_ansi_handle_exception(&msg, timer_exception_handler); + ok(count == 1, "expected count to be 1, got %d\n", count); + todo_wine + ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK || + broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */, + "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase); + + value = TRUE; + ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, + &value, sizeof(value)); + todo_wine + ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); + }
KillTimer(NULL, id); }
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/user32/message.c | 11 ++++++++++- dlls/user32/tests/msg.c | 6 ------ dlls/user32/user32.spec | 2 +- dlls/user32/user_main.c | 1 + dlls/user32/user_private.h | 1 + dlls/user32/winstation.c | 23 ++++++++++++++++++++++- 6 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index acab4117cf2..c3b90eeaf70 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -857,6 +857,15 @@ static LRESULT dispatch_message( const MSG *msg, BOOL ansi ) }
+static LONG WINAPI timerproc_exception_filter(EXCEPTION_POINTERS *eptr) +{ + if (suppress_timerproc_exception) + return EXCEPTION_EXECUTE_HANDLER; + + return EXCEPTION_CONTINUE_SEARCH; +} + + /*********************************************************************** * DispatchMessageA (USER32.@) * @@ -874,7 +883,7 @@ LRESULT WINAPI DECLSPEC_HOTPATCH DispatchMessageA( const MSG* msg ) retval = CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd, msg->message, msg->wParam, GetTickCount() ); } - __EXCEPT_ALL + __EXCEPT(timerproc_exception_filter) { retval = 0; } diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 960c57c9076..35576a0c32e 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -11424,7 +11424,6 @@ static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, value = FALSE; ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, &value, sizeof(value)); - todo_wine ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); tproc_exc_no_suppress = FALSE; } @@ -11657,14 +11656,12 @@ static void test_timers_exception(DWORD code) } else { - todo_wine ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError());
count = 0; timer_exc_phase = TIMER_EXCEPTION_INITIAL; dispatch_message_ansi_handle_exception(&msg, timer_exception_handler); ok(count == 1, "expected count to be 1, got %d\n", count); - todo_wine ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK || broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */, "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase); @@ -11672,7 +11669,6 @@ static void test_timers_exception(DWORD code) value = TRUE; ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, &value, sizeof(value)); - todo_wine ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError());
tproc_exc_no_suppress = TRUE; @@ -11680,7 +11676,6 @@ static void test_timers_exception(DWORD code) timer_exc_phase = TIMER_EXCEPTION_INITIAL; dispatch_message_ansi_handle_exception(&msg, timer_exception_handler); ok(count == 1, "expected count to be 1, got %d\n", count); - todo_wine ok(timer_exc_phase == TIMER_EXCEPTION_CONTINUE_OK || broken(timer_exc_phase == TIMER_EXCEPTION_RAISED) /* < win10 1507 */, "expected phase %d, got %d\n", TIMER_EXCEPTION_CONTINUE_OK, timer_exc_phase); @@ -11688,7 +11683,6 @@ static void test_timers_exception(DWORD code) value = TRUE; ret = SetUserObjectInformationW(GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, &value, sizeof(value)); - todo_wine ok(ret, "SetUserObjectInformationW error %lu\n", GetLastError()); }
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 96e6e1a7d6b..6a605ae4216 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -721,7 +721,7 @@ @ stdcall SetThreadDpiAwarenessContext(ptr) @ stdcall SetTimer(long long long ptr) @ stdcall SetUserObjectInformationA(long long ptr long) -@ stdcall SetUserObjectInformationW(long long ptr long) NtUserSetObjectInformation +@ stdcall SetUserObjectInformationW(long long ptr long) @ stdcall SetUserObjectSecurity(long ptr ptr) @ stdcall SetWinEventHook(long long long ptr long long long) @ stdcall SetWindowCompositionAttribute(ptr ptr) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index ef2b94ba698..f375462487b 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -29,6 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(graphics); WINE_DECLARE_DEBUG_CHANNEL(message);
HMODULE user32_module = 0; +BOOL suppress_timerproc_exception = TRUE;
extern void WDML_NotifyThreadDetach(void);
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 267c535defe..f6f1d490203 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -44,6 +44,7 @@ struct wm_char_mapping_data };
extern HMODULE user32_module DECLSPEC_HIDDEN; +extern BOOL suppress_timerproc_exception;
extern BOOL post_dde_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index 62593ca046f..789e45f8928 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -389,12 +389,33 @@ BOOL WINAPI GetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DW }
+/****************************************************************************** + * SetUserObjectInformationW (USER32.@) + */ +BOOL WINAPI SetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len ) +{ + if (index == UOI_TIMERPROC_EXCEPTION_SUPPRESSION) + { + if (handle != GetCurrentProcess() || len != sizeof(BOOL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + suppress_timerproc_exception = *(const BOOL *)info; + return TRUE; + } + + return NtUserSetObjectInformation( handle, index, info, len ); +} + + /****************************************************************************** * SetUserObjectInformationA (USER32.@) */ BOOL WINAPI SetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len ) { - return NtUserSetObjectInformation( handle, index, info, len ); + return SetUserObjectInformationW( handle, index, info, len ); }
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/win32u/tests/win32u.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index aaa27361206..f812e6bf16a 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -1829,6 +1829,39 @@ static void test_wndproc_hook(void) UnregisterClassW( L"TestLParamClass", NULL ); }
+static void test_NtUserSetObjectInformation(void) +{ + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( GetProcessWindowStation(), UOI_FLAGS, (void *)NULL, sizeof(USEROBJECTFLAGS) ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "NtUserSetObjectInformation error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( GetThreadDesktop(GetCurrentThreadId()), UOI_FLAGS, (void *)NULL, sizeof(USEROBJECTFLAGS) ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "NtUserSetObjectInformation error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)TRUE, 0 ); + todo_wine + ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)0xdeadbeef, 0xdeadbeef ); + todo_wine + ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)-1, -1 ); + todo_wine + ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + NtUserSetObjectInformation( NULL, UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)-1, -1 ); + todo_wine + ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() ); +} + START_TEST(win32u) { char **argv; @@ -1872,4 +1905,6 @@ START_TEST(win32u)
test_NtUserEnableMouseInPointer( argv, FALSE ); test_NtUserEnableMouseInPointer( argv, TRUE ); + + test_NtUserSetObjectInformation(); }
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/win32u/tests/win32u.c | 4 ---- dlls/win32u/winstation.c | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index f812e6bf16a..5b3740b436d 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -1843,22 +1843,18 @@ static void test_NtUserSetObjectInformation(void)
SetLastError( 0xdeadbeef ); NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)TRUE, 0 ); - todo_wine ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() );
SetLastError( 0xdeadbeef ); NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)0xdeadbeef, 0xdeadbeef ); - todo_wine ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() );
SetLastError( 0xdeadbeef ); NtUserSetObjectInformation( GetCurrentProcess(), UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)-1, -1 ); - todo_wine ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() );
SetLastError( 0xdeadbeef ); NtUserSetObjectInformation( NULL, UOI_TIMERPROC_EXCEPTION_SUPPRESSION, (void *)-1, -1 ); - todo_wine ok( GetLastError() == 0xdeadbeef, "NtUserSetObjectInformation error %lu\n", GetLastError() ); }
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 5d1d5254ae1..28131a0b2d5 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -395,6 +395,8 @@ BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DW BOOL ret; const USEROBJECTFLAGS *obj_flags = info;
+ if (index == UOI_TIMERPROC_EXCEPTION_SUPPRESSION) return TRUE; + if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags)) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=135405
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
user32: 2340:msg: unhandled exception c0000005 at 00007FFC0AE3428C