diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 3f7a4cd21c5..4e9a62c9820 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -43,6 +43,7 @@ #include "win.h" #include "controls.h" #include "wine/debug.h" +#include "wine/exception.h" WINE_DEFAULT_DEBUG_CHANNEL(msg); WINE_DECLARE_DEBUG_CHANNEL(relay); @@ -3065,8 +3066,20 @@ LRESULT WINAPI DispatchMessageA( const MSG* msg ) /* Process timer messages */ if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) { - if (msg->lParam) return CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd, - msg->message, msg->wParam, GetTickCount() ); + if (msg->lParam) + { + __TRY + { + retval = CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + __EXCEPT_PAGE_FAULT + { + retval = 0; + } + __ENDTRY + return retval; + } } if (!msg->hwnd) return 0; @@ -3103,7 +3116,8 @@ LRESULT WINAPI DispatchMessageA( const MSG* msg ) * If the lpMsg parameter points to a WM_TIMER message and the * parameter of the WM_TIMER message is not NULL, the lParam parameter * points to the function that is called instead of the window - * procedure. + * procedure. The function stored in lParam (timer callback) is protected + * from causing page-faults. * * The message must be valid. * @@ -3123,8 +3137,20 @@ LRESULT WINAPI DispatchMessageW( const MSG* msg ) /* Process timer messages */ if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) { - if (msg->lParam) return CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd, - msg->message, msg->wParam, GetTickCount() ); + if (msg->lParam) + { + __TRY + { + retval = CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + __EXCEPT_PAGE_FAULT + { + retval = 0; + } + __ENDTRY + return retval; + } } if (!msg->hwnd) return 0; diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 9208c9d997e..aeb1b62635d 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -7813,6 +7813,12 @@ static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime) { } +static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime) +{ + /* Crash on purpose */ + *(volatile int *)0 = 2; +} + #define TIMER_ID 0x19 static DWORD WINAPI timer_thread_proc(LPVOID x) @@ -7834,6 +7840,7 @@ static void test_timers(void) { struct timer_info info; DWORD id; + MSG msg; info.hWnd = CreateWindow ("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW , @@ -7855,6 +7862,12 @@ static void test_timers(void) ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n"); + /* Test timer callback with crash */ + info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash); + ok(info.id, "SetTimer failed\n"); + Sleep(150); + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg); + ok(DestroyWindow(info.hWnd), "failed to destroy window\n"); }