From: Piotr Caban Subject: Re: [PATCH] server: Don't wait for low level hook result when queueing hardware message. Message-Id: Date: Tue, 14 Sep 2021 18:38:38 +0200 In-Reply-To: References: I'm attaching a simple application that may be used to observe the problem. The application creates a window and waits for WM_KEYDOWN message. It deadlocks without the patch. Unfortunately there's no way of testing it without the ability to generate non-injected hardware messages. I can add an interactive test if it's preferred. Thanks, Piotr #include #include HANDLE start_event, end_event; HANDLE wake_up, sleep; static LRESULT WINAPI hook_proc(int code, WPARAM wparam, LPARAM lparam) { printf("hook called %x %x %lx\n", code, wparam, lparam); return CallNextHookEx(0, code, wparam, lparam); } static DWORD WINAPI hook_thread(void *arg) { HANDLE wait[2] = {wake_up, end_event}; HHOOK hook; DWORD ret; MSG msg; hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, 0, 0); SetEvent(start_event); while(1) { ret = WaitForMultipleObjects(2, wait, FALSE, INFINITE); if (ret == WAIT_OBJECT_0 + 1) break; PeekMessageA(&msg, 0, 0, 0, 0); SetEvent(sleep); } UnhookWindowsHookEx(hook); return 0; } int main() { HANDLE thread; HWND hwnd; MSG msg; start_event = CreateEventA(0, 0, 0, 0); end_event = CreateEventA(0, 0, 0, 0); wake_up = CreateEventA(0, 0, 0, 0); sleep = CreateEventA(0, 0, 0, 0); thread = CreateThread(0, 0, hook_thread, 0, 0, 0); WaitForSingleObject(start_event, INFINITE); hwnd = CreateWindowA("button", "button", WS_POPUP | WS_VISIBLE, 50, 50, 100, 100, 0, 0, 0, 0); while(1) { /* make sure that hook_thread message loop is not hung */ DWORD ret = MsgWaitForMultipleObjects(0, NULL, 0, 100, QS_ALLINPUT); msg.message = 0; if (ret == WAIT_OBJECT_0) { while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.message == WM_KEYDOWN) { printf("got WM_KEYDOWN\n"); break; } DispatchMessageA(&msg); } } if (msg.message == WM_KEYDOWN) break; SetEvent(wake_up); WaitForSingleObject(sleep, INFINITE); } SetEvent(end_event); WaitForSingleObject(thread, INFINITE); CloseHandle(hook_thread); CloseHandle(start_event); CloseHandle(end_event); CloseHandle(wake_up); CloseHandle(sleep); return 0; }