dinput: [2/2] Create/destroy hook thread from DirectInput [try 3].

Vitaliy Margolen wine-patch at kievinfo.com
Sun Sep 10 17:48:13 CDT 2006


Resend. I guess it got lost.

ChangeLog:
dinput: Create/destroy hook thread from DirectInput [try 3].

Changes from previous try:
- Use critical section instead of InterlockedXX
- Split into move & change

We need to create/destroy hook_thread independently from hooks. It owns
a window that have to be destroyed before unloading dll.

Fixes bug 4973.

 dlls/dinput/dinput_main.c |   75
++++++++++++++++++++++++++++-----------------
 1 files changed, 46 insertions(+), 29 deletions(-)



-------------- next part --------------
d4519a59c76ac1292dd6456de0cd6763486c6d2f
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index 2a05347..7ee01a3 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;
 }
 
@@ -735,19 +741,21 @@ static LRESULT CALLBACK dinput_hook_WndP
         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)
 {
     static const WCHAR classW[]={'H','o','o','k','_','L','L','_','C','L',0};
     MSG msg;
     WNDCLASSEXW wcex;
-    HWND hwnd;
 
     memset(&wcex, 0, sizeof(wcex));
     wcex.cbSize = sizeof(wcex);
@@ -756,11 +764,10 @@ static DWORD WINAPI hook_thread_proc(voi
     wcex.hInstance = GetModuleHandleW(0);
 
     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 = CreateWindowExW(0, classW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, 0);
 
-    SetEvent(signal_event);
-    if (hwnd)
+    SetEvent(*(LPHANDLE)param);
+    if (hook_thread_hwnd)
     {
         while (GetMessageW(&msg, 0, 0, 0))
         {
@@ -770,7 +777,8 @@ static DWORD WINAPI hook_thread_proc(voi
     }
     else ERR("Error creating message window\n");
 
-    DestroyWindow(hwnd);
+    DestroyWindow(hook_thread_hwnd);
+    hook_thread_hwnd = 0;
     UnregisterClassW(wcex.lpszClassName, wcex.hInstance);
     return 0;
 }
@@ -784,41 +792,50 @@ 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;
+            HANDLE handles[2] = {event, 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) SendMessageW(hook_thread_hwnd, WM_DESTROY, 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);
 }





More information about the wine-patches mailing list