From ed04d36b5dbb6a1b2eedcb73739a938142cfc38d Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Thu, 27 Jan 2005 11:14:19 +0000 Subject: [PATCH] Add more tests for old style hooks and winevent hooks, make them pass under Wine. --- dlls/user/hook.c | 8 +- dlls/user/tests/msg.c | 473 +++++++++++++++++++++++++++++++++++++++--- server/hook.c | 14 +- server/trace.c | 1 + 4 files changed, 462 insertions(+), 34 deletions(-) diff --git a/dlls/user/hook.c b/dlls/user/hook.c index cfc975963d..847849f365 100644 --- a/dlls/user/hook.c +++ b/dlls/user/hook.c @@ -124,6 +124,12 @@ static HHOOK set_windows_hook( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid, WCHAR module[MAX_PATH]; DWORD len; + if (!proc) + { + SetLastError( ERROR_INVALID_FILTER_PROC ); + return 0; + } + if (tid) /* thread-local hook */ { if (id == WH_JOURNALRECORD || @@ -143,7 +149,7 @@ static HHOOK set_windows_hook( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid, if (id == WH_KEYBOARD_LL || id == WH_MOUSE_LL) inst = 0; else if (!inst || !(len = GetModuleFileNameW( inst, module, MAX_PATH )) || len >= MAX_PATH) { - SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError( ERROR_HOOK_NEEDS_HMOD ); return 0; } } diff --git a/dlls/user/tests/msg.c b/dlls/user/tests/msg.c index a5cc4969f0..6f3c40ce0f 100644 --- a/dlls/user/tests/msg.c +++ b/dlls/user/tests/msg.c @@ -4510,6 +4510,7 @@ static BOOL RegisterWindowClasses(void) } static HHOOK hCBT_hook; +static DWORD cbt_hook_thread_id; static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) { @@ -4517,12 +4518,14 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam); + ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n"); + if (nCode == HCBT_SYSCOMMAND) { struct message msg; msg.message = nCode; - msg.flags = hook; + msg.flags = hook|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; add_message(&msg); @@ -4535,16 +4538,17 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) if (GetClassNameA((HWND)wParam, buf, sizeof(buf))) { - if (!strcmp(buf, "TestWindowClass") || - !strcmp(buf, "TestParentClass") || - !strcmp(buf, "TestPopupClass") || - !strcmp(buf, "SimpleWindowClass") || - !strcmp(buf, "TestDialogClass") || - !strcmp(buf, "MDI_frame_class") || - !strcmp(buf, "MDI_client_class") || - !strcmp(buf, "MDI_child_class") || - !strcmp(buf, "my_button_class") || - !strcmp(buf, "#32770")) + if (!lstrcmpiA(buf, "TestWindowClass") || + !lstrcmpiA(buf, "TestParentClass") || + !lstrcmpiA(buf, "TestPopupClass") || + !lstrcmpiA(buf, "SimpleWindowClass") || + !lstrcmpiA(buf, "TestDialogClass") || + !lstrcmpiA(buf, "MDI_frame_class") || + !lstrcmpiA(buf, "MDI_client_class") || + !lstrcmpiA(buf, "MDI_child_class") || + !lstrcmpiA(buf, "my_button_class") || + !lstrcmpiA(buf, "static") || + !lstrcmpiA(buf, "#32770")) { struct message msg; @@ -4571,22 +4575,25 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent, trace("WEH:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n", hevent, event, hwnd, object_id, child_id, thread_id, event_time); + ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n"); + /* ignore mouse cursor events */ if (object_id == OBJID_CURSOR) return; if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf))) { if (!hwnd || - !strcmp(buf, "TestWindowClass") || - !strcmp(buf, "TestParentClass") || - !strcmp(buf, "TestPopupClass") || - !strcmp(buf, "SimpleWindowClass") || - !strcmp(buf, "TestDialogClass") || - !strcmp(buf, "MDI_frame_class") || - !strcmp(buf, "MDI_client_class") || - !strcmp(buf, "MDI_child_class") || - !strcmp(buf, "my_button_class") || - !strcmp(buf, "#32770")) + !lstrcmpiA(buf, "TestWindowClass") || + !lstrcmpiA(buf, "TestParentClass") || + !lstrcmpiA(buf, "TestPopupClass") || + !lstrcmpiA(buf, "SimpleWindowClass") || + !lstrcmpiA(buf, "TestDialogClass") || + !lstrcmpiA(buf, "MDI_frame_class") || + !lstrcmpiA(buf, "MDI_client_class") || + !lstrcmpiA(buf, "MDI_child_class") || + !lstrcmpiA(buf, "my_button_class") || + !lstrcmpiA(buf, "static") || + !lstrcmpiA(buf, "#32770")) { struct message msg; @@ -4751,6 +4758,9 @@ static void test_timers(void) WaitForSingleObject(info.handles[1], INFINITE); + CloseHandle(info.handles[0]); + CloseHandle(info.handles[1]); + ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n"); ok(DestroyWindow(info.hWnd), "failed to destroy window\n"); @@ -4784,40 +4794,434 @@ static const struct message WmWinEventsSeq[] = { { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 }, { 0 } }; +static const struct message WmWinEventCaretSeq[] = { + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */ + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */ + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */ + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */ + { 0 } +}; +static const struct message WmWinEventCaretSeq_2[] = { + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */ + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */ + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */ + { 0 } +}; +static const struct message WmWinEventAlertSeq[] = { + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 }, + { 0 } +}; +static const struct message WmWinEventAlertSeq_2[] = { + /* create window in the thread proc */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 }, + /* our test event */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 }, + { 0 } +}; +static const struct message WmGlobalHookSeq_1[] = { + /* create window in the thread proc */ + { HCBT_CREATEWND, hook|lparam, 0, 2 }, + /* our test events */ + { HCBT_SETFOCUS, hook|lparam, 0, 2 }, /* SetFocus(0) */ + { HCBT_ACTIVATE, hook|lparam, 0, 2 }, + { HCBT_SETFOCUS, hook|lparam, 0, 2 }, /* SetFocus(hwnd) */ + { 0 } +}; +static const struct message WmGlobalHookSeq_2[] = { + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */ + { 0 } +}; -static void test_winevents(void) +static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent, + DWORD event, + HWND hwnd, + LONG object_id, + LONG child_id, + DWORD thread_id, + DWORD event_time) +{ + char buf[256]; + + trace("WEH_2:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n", + hevent, event, hwnd, object_id, child_id, thread_id, event_time); + + if (GetClassNameA(hwnd, buf, sizeof(buf))) + { + if (!lstrcmpiA(buf, "TestWindowClass") || + !lstrcmpiA(buf, "static")) + { + struct message msg; + + msg.message = event; + msg.flags = winevent_hook|wparam|lparam; + msg.wParam = object_id; + msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2); + add_message(&msg); + } + } +} + +static HHOOK hCBT_global_hook; +static DWORD cbt_global_hook_thread_id; + +static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) +{ + char buf[256]; + + trace("CBT_2: %d, %08x, %08lx\n", nCode, wParam, lParam); + + if (nCode == HCBT_SYSCOMMAND) + { + struct message msg; + + msg.message = nCode; + msg.flags = hook|wparam|lparam; + msg.wParam = wParam; + msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2; + add_message(&msg); + + return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam); + } + + /* Log also SetFocus(0) calls */ + if (!wParam) wParam = lParam; + + if (GetClassNameA((HWND)wParam, buf, sizeof(buf))) + { + if (!lstrcmpiA(buf, "TestWindowClass") || + !lstrcmpiA(buf, "static")) + { + struct message msg; + + msg.message = nCode; + msg.flags = hook|wparam|lparam; + msg.wParam = wParam; + msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2; + add_message(&msg); + } + } + return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam); +} + +static DWORD WINAPI win_event_global_thread_proc(void *param) { HWND hwnd; + MSG msg; + HANDLE hevent = *(HANDLE *)param; + HMODULE user32 = GetModuleHandleA("user32.dll"); + FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent"); + + assert(pNotifyWinEvent); + + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); + assert(hwnd); + trace("created thread window %p\n", hwnd); + + *(HWND *)param = hwnd; + + flush_sequence(); + /* this event should be received only by our new hook proc, + * an old one does not expect an event from another thread. + */ + pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0); + SetEvent(hevent); + + while (GetMessage(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +static DWORD WINAPI cbt_global_hook_thread_proc(void *param) +{ + HWND hwnd; + MSG msg; + HANDLE hevent = *(HANDLE *)param; + + flush_sequence(); + /* these events should be received only by our new hook proc, + * an old one does not expect an event from another thread. + */ + + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); + assert(hwnd); + trace("created thread window %p\n", hwnd); + + *(HWND *)param = hwnd; + + /* generate focus related CBT events */ + SetFocus(0); + SetFocus(hwnd); + + SetEvent(hevent); + + while (GetMessage(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +static void test_winevents(void) +{ + MSG msg; + HWND hwnd, hwnd2; UINT i; + HANDLE hthread, hevent; + DWORD tid; + HWINEVENTHOOK hhook; const struct message *events = WmWinEventsSeq; HMODULE user32 = GetModuleHandleA("user32.dll"); + FARPROC pSetWinEventHook = 0;/*GetProcAddress(user32, "SetWinEventHook");*/ + FARPROC pUnhookWinEvent = 0;/*GetProcAddress(user32, "UnhookWinEvent");*/ FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent"); - if (!pNotifyWinEvent) return; - - hwnd = CreateWindow ("TestWindowClass", NULL, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, - NULL, NULL, 0); + hwnd = CreateWindowExA(0, "TestWindowClass", NULL, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, + NULL, NULL, 0); assert(hwnd); + /****** start of global hook test *************/ + hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0); + assert(hCBT_global_hook); + + hevent = CreateEventA(NULL, 0, 0, NULL); + assert(hevent); + hwnd2 = (HWND)hevent; + + hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); + + ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + + ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE); + + flush_sequence(); + /* this one should be received only by old hook proc */ + DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0); + /* this one should be received only by old hook proc */ + DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0); + + ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE); + + ok(UnhookWindowsHookEx(hCBT_global_hook), "UnhookWindowsHookEx error %ld", GetLastError()); + + PostThreadMessageA(tid, WM_QUIT, 0, 0); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + CloseHandle(hevent); + ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n"); + /****** end of global hook test *************/ + + if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent) + { + ok(DestroyWindow(hwnd), "failed to destroy window\n"); + return; + } + flush_sequence(); - /* Windows ignores events with hwnd == 0 */ +#if 0 /* this test doesn't pass under Win9x */ + /* win2k ignores events with hwnd == 0 */ SetLastError(0xdeadbeef); pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */ GetLastError() == 0xdeadbeef, /* Win9x */ "unexpected error %ld\n", GetLastError()); ok_sequence(WmEmptySeq, "empty notify winevents", FALSE); +#endif for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++) pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam); ok_sequence(WmWinEventsSeq, "notify winevents", FALSE); + + /****** start of event filtering test *************/ + hhook = (HWINEVENTHOOK)pSetWinEventHook( + EVENT_OBJECT_SHOW, /* 0x8002 */ + EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */ + GetModuleHandleA(0), win_event_global_hook_proc, + GetCurrentProcessId(), 0, + WINEVENT_INCONTEXT); + ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError()); + + hevent = CreateEventA(NULL, 0, 0, NULL); + assert(hevent); + hwnd2 = (HWND)hevent; + + hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); + + ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + + ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE); + + flush_sequence(); + /* this one should be received only by old hook proc */ + pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */ + pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */ + /* this one should be received only by old hook proc */ + pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */ + + ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE); + + ok(pUnhookWinEvent(hhook), "UnhookWinEvent error %ld\n", GetLastError()); + + PostThreadMessageA(tid, WM_QUIT, 0, 0); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + CloseHandle(hevent); + ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n"); + /****** end of event filtering test *************/ + + /****** start of out of context event test *************/ + hhook = (HWINEVENTHOOK)pSetWinEventHook( + EVENT_MIN, EVENT_MAX, + 0, win_event_global_hook_proc, + GetCurrentProcessId(), 0, + WINEVENT_OUTOFCONTEXT); + ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError()); + + hevent = CreateEventA(NULL, 0, 0, NULL); + assert(hevent); + hwnd2 = (HWND)hevent; + + flush_sequence(); + + hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); + + ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + + ok_sequence(WmEmptySeq, "empty notify winevents", FALSE); + /* process pending winevent messages */ + ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n"); + ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE); + + flush_sequence(); + /* this one should be received only by old hook proc */ + pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */ + pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */ + /* this one should be received only by old hook proc */ + pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */ + + ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE); + /* process pending winevent messages */ + ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n"); + ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE); + + ok(pUnhookWinEvent(hhook), "UnhookWinEvent error %ld\n", GetLastError()); + + PostThreadMessageA(tid, WM_QUIT, 0, 0); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + CloseHandle(hevent); + ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n"); + /****** end of out of context event test *************/ + ok(DestroyWindow(hwnd), "failed to destroy window\n"); } +static void test_set_hook(void) +{ + HHOOK hhook; + HWINEVENTHOOK hwinevent_hook; + HMODULE user32 = GetModuleHandleA("user32.dll"); + FARPROC pSetWinEventHook = 0;/*GetProcAddress(user32, "SetWinEventHook");*/ + FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent"); + + hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId()); + ok(hhook != 0, "local hook does not require hModule set to 0\n"); + UnhookWindowsHookEx(hhook); + +#if 0 /* this test doesn't pass under Win9x: BUG! */ + SetLastError(0xdeadbeef); + hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0); + ok(!hhook, "global hook requires hModule != 0\n"); + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError()); +#endif + + SetLastError(0xdeadbeef); + hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId()); + ok(!hhook, "SetWinEventHook with invalid proc should fail\n"); + ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */ + GetLastError() == 0xdeadbeef, /* Win9x */ + "unexpected error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n"); + ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */ + GetLastError() == 0xdeadbeef, /* Win9x */ + "unexpected error %ld\n", GetLastError()); + + if (!pSetWinEventHook || !pUnhookWinEvent) return; + + /* even process local incontext hooks require hmodule */ + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, + 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ + GetLastError() == 0xdeadbeef, /* Win9x */ + "unexpected error %ld\n", GetLastError()); + + /* even thread local incontext hooks require hmodule */ + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, + 0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT); + ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ + GetLastError() == 0xdeadbeef, /* Win9x */ + "unexpected error %ld\n", GetLastError()); + +#if 0 /* these 3 tests don't pass under Win9x */ + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0, + 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); + ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1, + 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); + ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, + 0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT); + ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n"); + ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError()); +#endif + + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0, + 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError()); + ok(pUnhookWinEvent(hwinevent_hook), "UnhookWinEvent error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, + 0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT); + ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError()); + ok(pUnhookWinEvent(hwinevent_hook), "UnhookWinEvent error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */ + GetLastError() == 0xdeadbeef, /* Win9x */ + "unexpected error %ld\n", GetLastError()); +} + START_TEST(msg) { HMODULE user32 = GetModuleHandleA("user32.dll"); @@ -4829,22 +5233,28 @@ START_TEST(msg) if (pSetWinEventHook) { - UINT event; hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandleA(0), win_event_proc, - GetCurrentProcessId(), 0, + GetCurrentThreadId(), WINEVENT_INCONTEXT); assert(hEvent_hook); if (pIsWinEventHookInstalled) { + UINT event; for (event = EVENT_MIN; event <= EVENT_MAX; event++) ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event); } + + /* Fix message sequences before removing 3 lines below */ + ok(pUnhookWinEvent(hEvent_hook), "UnhookWinEvent error %ld\n", GetLastError()); + pUnhookWinEvent = 0; + hEvent_hook = 0; } + cbt_hook_thread_id = GetCurrentThreadId(); hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); assert(hCBT_hook); @@ -4856,6 +5266,7 @@ START_TEST(msg) test_message_conversion(); test_accelerators(); test_timers(); + test_set_hook(); test_winevents(); UnhookWindowsHookEx(hCBT_hook); diff --git a/server/hook.c b/server/hook.c index ab868659ea..b26911481b 100644 --- a/server/hook.c +++ b/server/hook.c @@ -320,7 +320,14 @@ DECL_HANDLER(remove_hook) { struct hook *hook; - if (req->handle) hook = get_user_object( req->handle, USER_HOOK ); + if (req->handle) + { + if (!(hook = get_user_object( req->handle, USER_HOOK ))) + { + set_win32_error( ERROR_INVALID_HOOK_HANDLE ); + return; + } + } else { if (!req->proc || req->id < WH_MINHOOK || req->id > WH_MAXHOOK) @@ -329,9 +336,12 @@ DECL_HANDLER(remove_hook) return; } if (!(hook = find_hook( current, req->id - WH_MINHOOK, req->proc ))) + { set_error( STATUS_INVALID_PARAMETER ); + return; + } } - if (hook) remove_hook( hook ); + remove_hook( hook ); } diff --git a/server/trace.c b/server/trace.c index 38d4c894da..d54294dbf8 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3210,6 +3210,7 @@ static const char *get_status_name( unsigned int status ) NAME(TIMEOUT), NAME(USER_APC), NAME(WAS_LOCKED), + NAME_WIN32(ERROR_INVALID_HOOK_HANDLE), NAME_WIN32(ERROR_INVALID_INDEX), NAME_WIN32(ERROR_NEGATIVE_SEEK), NAME_WIN32(ERROR_SEEK), -- 2.32.0.93.g670b81a890