[PATCH 4/4] xinput1_3: Register device notifications in DllMain.

Rémi Bernon rbernon at codeweavers.com
Thu Dec 23 08:33:11 CST 2021


Instead of doing it lazily, which is more likely to be after the game
has registered theirs. As the message handling order is the same as the
registration, XInput may end updating its device list only too late,
every time.

Some games register device notifications and call XInputGetCapabilities
or XInputGetState from their window proc, expecting XInput controller
list to be updated already. If the controller is missing they won't try
calling XInput functions again until another WM_DEVICECHANGE message is
received.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/xinput1_3/main.c | 55 ++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 27 deletions(-)

diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c
index 506802d142a..4536b027dc2 100644
--- a/dlls/xinput1_3/main.c
+++ b/dlls/xinput1_3/main.c
@@ -119,7 +119,8 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] =
     {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }},
 };
 
-static HMODULE xinput_instance;
+static HDEVNOTIFY update_devnotify;
+static HWND update_hwnd;
 static HANDLE start_event;
 static HANDLE stop_event;
 static HANDLE done_event;
@@ -654,34 +655,14 @@ static DWORD WINAPI hid_update_thread_proc(void *param)
     struct xinput_controller *devices[XUSER_MAX_COUNT + 2];
     HANDLE events[XUSER_MAX_COUNT + 2];
     DWORD i, count = 2, ret = WAIT_TIMEOUT;
-    DEV_BROADCAST_DEVICEINTERFACE_W filter =
-    {
-        .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W),
-        .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
-        .dbcc_classguid = GUID_DEVINTERFACE_WINEXINPUT,
-    };
-    WNDCLASSEXW cls =
-    {
-        .cbSize = sizeof(WNDCLASSEXW),
-        .hInstance = xinput_instance,
-        .lpszClassName = L"__wine_xinput_devnotify",
-        .lpfnWndProc = xinput_devnotify_wndproc,
-    };
-    HDEVNOTIFY notif;
-    HWND hwnd;
     MSG msg;
 
-    RegisterClassExW(&cls);
-    hwnd = CreateWindowExW(0, cls.lpszClassName, NULL, 0, 0, 0, 0, 0,
-                           HWND_MESSAGE, NULL, NULL, NULL);
-    notif = RegisterDeviceNotificationW(hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
-
     update_controller_list();
     SetEvent(start_event);
 
     do
     {
-        if (ret == count) while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
+        if (ret == count) while (PeekMessageW(&msg, update_hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
         if (ret == WAIT_TIMEOUT) update_controller_list();
         if (ret < count - 2) read_controller_state(devices[ret]);
 
@@ -704,10 +685,6 @@ static DWORD WINAPI hid_update_thread_proc(void *param)
     while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) < count - 1 ||
             ret == count || ret == WAIT_TIMEOUT);
 
-    UnregisterDeviceNotification(notif);
-    DestroyWindow(hwnd);
-    UnregisterClassW(cls.lpszClassName, xinput_instance);
-
     if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret);
     SetEvent(done_event);
     return ret;
@@ -765,15 +742,39 @@ static void controller_unlock(struct xinput_controller *controller)
 
 BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
 {
+    DEV_BROADCAST_DEVICEINTERFACE_W filter =
+    {
+        .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W),
+        .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
+        .dbcc_classguid = GUID_DEVINTERFACE_WINEXINPUT,
+    };
+    WNDCLASSEXW class =
+    {
+        .cbSize = sizeof(WNDCLASSEXW),
+        .hInstance = inst,
+        .lpszClassName = L"__wine_xinput_devnotify",
+        .lpfnWndProc = xinput_devnotify_wndproc,
+    };
+
+    TRACE("inst %p, reason %u, reserved %p.\n", inst, reason, reserved);
+
     switch (reason)
     {
     case DLL_PROCESS_ATTACH:
-        xinput_instance = inst;
         DisableThreadLibraryCalls(inst);
+
+        RegisterClassExW(&class);
+        update_hwnd = CreateWindowExW(0, class.lpszClassName, NULL, 0, 0, 0, 0, 0,
+                                      HWND_MESSAGE, NULL, NULL, NULL);
+        update_devnotify = RegisterDeviceNotificationW(update_hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
         break;
     case DLL_PROCESS_DETACH:
         if (reserved) break;
         stop_update_thread();
+
+        UnregisterDeviceNotification(update_devnotify);
+        DestroyWindow(update_hwnd);
+        UnregisterClassW(class.lpszClassName, class.hInstance);
         break;
     }
     return TRUE;
-- 
2.34.1




More information about the wine-devel mailing list