Module: wine Branch: master Commit: ad045d6e8142d8fd197a8d445670a3fc95dfcda2 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=ad045d6e8142d8fd197a8d44...
Author: Vitaliy Margolen wine-patch@kievinfo.com Date: Wed Sep 13 00:06:15 2006 -0600
dinput: Create/destroy hook thread from DirectInput.
---
dlls/dinput/dinput_main.c | 78 +++++++++++++++++++++++++++++++-------------- 1 files changed, 53 insertions(+), 25 deletions(-)
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 2a05347..b60cd89 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -76,6 +76,8 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWO return TRUE; }
+static BOOL create_hook_thread(void); +static void release_hook_thread(void);
/****************************************************************************** * DirectInputCreateEx (DINPUT.@) @@ -118,6 +120,7 @@ HRESULT WINAPI DirectInputCreateEx( res = DI_OK; }
+ if (res == DI_OK && !create_hook_thread()) res = DIERR_GENERIC; if (res == DI_OK) { This = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectInputImpl)); @@ -255,7 +258,10 @@ static ULONG WINAPI IDirectInputAImpl_Re ULONG ref; ref = InterlockedDecrement(&(This->ref)); if (ref == 0) - HeapFree(GetProcessHeap(),0,This); + { + HeapFree(GetProcessHeap(), 0, This); + release_hook_thread(); + } return ref; }
@@ -732,15 +738,21 @@ static LRESULT CALLBACK dinput_hook_WndP return res; } } + else if (!wParam && !lParam) + DestroyWindow(hWnd); + return 0;
case WM_DESTROY: + if (kbd_hook) UnhookWindowsHookEx(kbd_hook); + if (mouse_hook) UnhookWindowsHookEx(mouse_hook); PostQuitMessage(0); } return DefWindowProcW(hWnd, message, wParam, lParam); }
-static HANDLE signal_event; +static HWND hook_thread_hwnd; +static LONG hook_thread_refcount;
static DWORD WINAPI hook_thread_proc(void *param) { @@ -757,9 +769,9 @@ static DWORD WINAPI hook_thread_proc(voi
if (!RegisterClassExW(&wcex)) ERR("Error registering window class\n"); hwnd = CreateWindowExW(0, classW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, 0); - *(HWND*)param = hwnd; + hook_thread_hwnd = hwnd;
- SetEvent(signal_event); + SetEvent(*(LPHANDLE)param); if (hwnd) { while (GetMessageW(&msg, 0, 0, 0)) @@ -767,10 +779,10 @@ static DWORD WINAPI hook_thread_proc(voi TranslateMessage(&msg); DispatchMessageW(&msg); } + DestroyWindow(hwnd); } else ERR("Error creating message window\n");
- DestroyWindow(hwnd); UnregisterClassW(wcex.lpszClassName, wcex.hInstance); return 0; } @@ -784,41 +796,57 @@ static CRITICAL_SECTION_DEBUG dinput_cri }; static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
-static HWND get_thread_hwnd(void) +static BOOL create_hook_thread(void) { - static HANDLE hook_thread; - static HWND hook_thread_hwnd; + LONG ref;
EnterCriticalSection(&dinput_hook_crit); - if (!hook_thread) + ref = ++hook_thread_refcount; + TRACE("Refcount %ld\n", ref); + if (ref == 1) { DWORD tid; - HWND hwnd; + HANDLE thread, event;
- signal_event = CreateEventW(NULL, FALSE, FALSE, NULL); - hook_thread = CreateThread(NULL, 0, hook_thread_proc, &hwnd, 0, &tid); - if (signal_event && hook_thread) + event = CreateEventW(NULL, FALSE, FALSE, NULL); + thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &tid); + if (event && thread) { HANDLE handles[2]; - handles[0] = signal_event; - handles[1] = hook_thread; + handles[0] = event; + handles[1] = thread; WaitForMultipleObjects(2, handles, FALSE, INFINITE); } - CloseHandle(signal_event); - - if (!(hook_thread_hwnd = hwnd)) - { - /* Thread failed to create window - reset things so we could try again later */ - CloseHandle(hook_thread); - hook_thread = 0; - } + CloseHandle(event); + CloseHandle(thread); } LeaveCriticalSection(&dinput_hook_crit);
- return hook_thread_hwnd; + return hook_thread_hwnd != 0; +} + +static void release_hook_thread(void) +{ + LONG ref; + + EnterCriticalSection(&dinput_hook_crit); + ref = --hook_thread_refcount; + TRACE("Releasing to %ld\n", ref); + if (ref == 0) + { + HWND hwnd = hook_thread_hwnd; + hook_thread_hwnd = 0; + SendMessageW(hwnd, WM_USER+0x10, 0, 0); + } + LeaveCriticalSection(&dinput_hook_crit); }
HHOOK set_dinput_hook(int hook_id, LPVOID proc) { - return (HHOOK)SendMessageW(get_thread_hwnd(), WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc); + HWND hwnd; + + EnterCriticalSection(&dinput_hook_crit); + hwnd = hook_thread_hwnd; + LeaveCriticalSection(&dinput_hook_crit); + return (HHOOK)SendMessageW(hwnd, WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc); }