dinput: Create/destroy hook thread from DirectInput.

Vitaliy Margolen wine-patch at kievinfo.com
Mon Aug 21 18:30:03 CDT 2006


ChangeLog:
dinput: Create/destroy hook thread from DirectInput.
Move hook thread into more appropriate place

This will guarantee that we create and destroy thread at the right
time. And that we will have only one thread per process.

Fixes bug 4973.

 dlls/dinput/device.c         |  136 ------------------------------------------
 dlls/dinput/device_private.h |    2 -
 dlls/dinput/dinput_main.c    |  135 +++++++++++++++++++++++++++++++++++++++++-
 dlls/dinput/dinput_private.h |    2 +
 4 files changed, 136 insertions(+), 139 deletions(-)
-------------- next part --------------
be6a0e645a3f46f4f917713eace0629e595a562a
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 5c0234f..51ee255 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -901,139 +901,3 @@ HRESULT WINAPI IDirectInputDevice8WImpl_
     
     return DI_OK;
 }
-
-/******************************************************************************
- *	DInput hook thread
- */
-
-static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-    static HHOOK kbd_hook, mouse_hook;
-    BOOL res;
-
-    TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam);
-    switch (message)
-    {
-    case WM_USER+0x10:
-        if (wParam == WH_KEYBOARD_LL)
-        {
-            if (lParam)
-            {
-                if (kbd_hook) return 0;
-                kbd_hook = SetWindowsHookExW(WH_KEYBOARD_LL, (LPVOID)lParam, DINPUT_instance, 0);
-                return (LRESULT)kbd_hook;
-            }
-            else
-            {
-                if (!kbd_hook) return 0;
-                res = UnhookWindowsHookEx(kbd_hook);
-                kbd_hook = NULL;
-                return res;
-            }
-        }
-        else if (wParam == WH_MOUSE_LL)
-        {
-            if (lParam)
-            {
-                if (mouse_hook) return 0;
-                mouse_hook = SetWindowsHookExW(WH_MOUSE_LL, (LPVOID)lParam, DINPUT_instance, 0);
-                return (LRESULT)mouse_hook;
-            }
-            else
-            {
-                if (!mouse_hook) return 0;
-                res = UnhookWindowsHookEx(mouse_hook);
-                mouse_hook = NULL;
-                return res;
-            }
-        }
-        return 0;
-
-    case WM_DESTROY:
-        PostQuitMessage(0);
-    }
-    return DefWindowProcW(hWnd, message, wParam, lParam);
-}
-
-static HANDLE signal_event;
-
-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);
-    wcex.lpfnWndProc = dinput_hook_WndProc;
-    wcex.lpszClassName = classW;
-    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;
-
-    SetEvent(signal_event);
-    if (hwnd)
-    {
-        while (GetMessageW(&msg, 0, 0, 0))
-        {
-            TranslateMessage(&msg);
-            DispatchMessageW(&msg);
-        }
-    }
-    else ERR("Error creating message window\n");
-
-    DestroyWindow(hwnd);
-    UnregisterClassW(wcex.lpszClassName, wcex.hInstance);
-    return 0;
-}
-
-static CRITICAL_SECTION dinput_hook_crit;
-static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
-{
-    0, 0, &dinput_hook_crit,
-    { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
-};
-static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
-
-static HWND get_thread_hwnd(void)
-{
-    static HANDLE hook_thread;
-    static HWND   hook_thread_hwnd;
-
-    EnterCriticalSection(&dinput_hook_crit);
-    if (!hook_thread)
-    {
-        DWORD tid;
-        HWND hwnd;
-
-        signal_event = CreateEventW(NULL, FALSE, FALSE, NULL);
-        hook_thread = CreateThread(NULL, 0, hook_thread_proc, &hwnd, 0, &tid);
-        if (signal_event && hook_thread)
-        {
-            HANDLE handles[2];
-            handles[0] = signal_event;
-            handles[1] = hook_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;
-        }
-    }
-    LeaveCriticalSection(&dinput_hook_crit);
-
-    return hook_thread_hwnd;
-}
-
-HHOOK set_dinput_hook(int hook_id, LPVOID proc)
-{
-    return (HHOOK)SendMessageW(get_thread_hwnd(), WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc);
-}
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 8ccd0ab..a2777c2 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -52,8 +52,6 @@ extern void fill_DataFormat(void *out, c
 extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ;
 extern void release_DataFormat(DataFormat *df) ;
 
-extern HHOOK set_dinput_hook(int hook_id, LPVOID proc);
-
 /* Used to fill events in the queue */
 #define GEN_EVENT(offset,data,xtime,seq)					\
 {										\
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index cef61b7..5e121b7 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;
 }
 
@@ -686,3 +692,130 @@ HRESULT WINAPI DllGetClassObject(REFCLSI
     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
     return CLASS_E_CLASSNOTAVAILABLE;
 }
+
+/******************************************************************************
+ *	DInput hook thread
+ */
+
+static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static HHOOK kbd_hook, mouse_hook;
+    BOOL res;
+
+    TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam);
+    switch (message)
+    {
+    case WM_USER+0x10:
+        if (wParam == WH_KEYBOARD_LL)
+        {
+            if (lParam)
+            {
+                if (kbd_hook) return 0;
+                kbd_hook = SetWindowsHookExW(WH_KEYBOARD_LL, (LPVOID)lParam, DINPUT_instance, 0);
+                return (LRESULT)kbd_hook;
+            }
+            else
+            {
+                if (!kbd_hook) return 0;
+                res = UnhookWindowsHookEx(kbd_hook);
+                kbd_hook = NULL;
+                return res;
+            }
+        }
+        else if (wParam == WH_MOUSE_LL)
+        {
+            if (lParam)
+            {
+                if (mouse_hook) return 0;
+                mouse_hook = SetWindowsHookExW(WH_MOUSE_LL, (LPVOID)lParam, DINPUT_instance, 0);
+                return (LRESULT)mouse_hook;
+            }
+            else
+            {
+                if (!mouse_hook) return 0;
+                res = UnhookWindowsHookEx(mouse_hook);
+                mouse_hook = NULL;
+                return res;
+            }
+        }
+        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 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;
+
+    memset(&wcex, 0, sizeof(wcex));
+    wcex.cbSize = sizeof(wcex);
+    wcex.lpfnWndProc = dinput_hook_WndProc;
+    wcex.lpszClassName = classW;
+    wcex.hInstance = GetModuleHandleW(0);
+
+    if (!RegisterClassExW(&wcex)) ERR("Error registering window class\n");
+    hook_thread_hwnd = CreateWindowExW(0, classW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, 0);
+
+    SetEvent(*(LPHANDLE)param);
+    if (hook_thread_hwnd)
+    {
+        while (GetMessageW(&msg, 0, 0, 0))
+        {
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+    }
+    else ERR("Error creating message window\n");
+
+    DestroyWindow(hook_thread_hwnd);
+    UnregisterClassW(wcex.lpszClassName, wcex.hInstance);
+    return 0;
+}
+
+static BOOL create_hook_thread(void)
+{
+    LONG ref;
+
+    ref = InterlockedIncrement(&hook_thread_refcount);
+    TRACE("Refcount %ld\n", ref);
+    if (ref == 1)
+    {
+        DWORD tid;
+        HANDLE thread, event;
+
+        event = CreateEventW(NULL, FALSE, FALSE, NULL);
+        thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &tid);
+        if (event && thread)
+        {
+            HANDLE handles[2] = {event, thread};
+            WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+        }
+        CloseHandle(event);
+        CloseHandle(thread);
+    }
+    return hook_thread_hwnd != 0;
+}
+
+static void release_hook_thread(void)
+{
+    LONG ref;
+
+    ref = InterlockedDecrement(&hook_thread_refcount);
+    TRACE("Releasing to %ld\n", ref);
+    if (ref == 0) SendMessageW(hook_thread_hwnd, WM_DESTROY, 0, 0);
+}
+
+HHOOK set_dinput_hook(int hook_id, LPVOID proc)
+{
+    return (HHOOK)SendMessageW(hook_thread_hwnd, WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc);
+}
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index c23b048..d3f58a3 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -54,4 +54,6 @@ extern const struct dinput_device joysti
 
 extern HINSTANCE DINPUT_instance;
 
+extern HHOOK set_dinput_hook(int hook_id, LPVOID proc);
+
 #endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */


More information about the wine-patches mailing list