Add more tests for old style hooks and winevent hooks, make them pass under Wine

Dmitry Timoshkov dmitry at baikal.ru
Wed Jan 26 05:39:31 CST 2005


Hello,

while working on a winevents implementation I wrote a lot of tests
for both old style hooks and winevent hooks. In order to make my life
a bit easier I'm sending that tests now, so I have less conflicts
in future.

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    Add more tests for old style hooks and winevent hooks, make them
    pass under Wine.

diff -up cvs/hq/wine/dlls/user/hook.c wine/dlls/user/hook.c
--- cvs/hq/wine/dlls/user/hook.c	2005-01-06 15:17:36.000000000 +0800
+++ wine/dlls/user/hook.c	2005-01-26 19:02:50.000000000 +0800
@@ -124,6 +124,12 @@ static HHOOK set_windows_hook( INT id, H
     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, H
         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 -up cvs/hq/wine/dlls/user/tests/msg.c wine/dlls/user/tests/msg.c
--- cvs/hq/wine/dlls/user/tests/msg.c	2005-01-26 17:55:57.000000000 +0800
+++ wine/dlls/user/tests/msg.c	2005-01-26 19:03:40.000000000 +0800
@@ -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(in
 
     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(in
 
     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(HWIN
     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 WmWinEventsS
     { 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 -up cvs/hq/wine/server/hook.c wine/server/hook.c
--- cvs/hq/wine/server/hook.c	2003-09-09 15:36:41.000000000 +0900
+++ wine/server/hook.c	2005-01-26 18:59:14.000000000 +0800
@@ -332,6 +332,7 @@ DECL_HANDLER(remove_hook)
             set_error( STATUS_INVALID_PARAMETER );
     }
     if (hook) remove_hook( hook );
+    else set_win32_error( ERROR_INVALID_HOOK_HANDLE );
 }
 
 






More information about the wine-patches mailing list