[PATCH 0/2] MR2872: dinput: More BuildActionMap and work thread fixes.
From: Rémi Bernon <rbernon(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 --- dlls/dinput/device.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index b761b3e9d6d..427d3895700 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1866,6 +1866,23 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY; + /* check already mapped objects */ + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) + { + if (!action->dwHow || !action->dwObjID) continue; + if (!IsEqualGUID(&action->guidInstance, &impl->guid)) continue; + + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) + { + if (action->dwObjID != object->dwType) continue; + mapped[object - impl->device_format.rgodf] = TRUE; + break; + } + } + + /* map any unmapped priority 1 objects */ action_end = format->rgoAction + format->dwNumActions; for (action = format->rgoAction; action < action_end; action++) { @@ -1886,6 +1903,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, } } + /* map any unmapped priority 2 objects */ for (action = format->rgoAction; action < action_end; action++) { if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2872
From: Rémi Bernon <rbernon(a)codeweavers.com> Some applications create a IDirectInput and IDirectInputDevice instance from their DllMain procedure, and starting the thread on the first user creation and waiting for it to start will deadlock on the loader lock. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54916 --- dlls/dinput/dinput_main.c | 80 +++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 0d502821966..51e1a134023 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -89,28 +89,6 @@ static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0 static struct list acquired_device_list = LIST_INIT( acquired_device_list ); -void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) -{ - struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - - EnterCriticalSection( &dinput_hook_crit ); - list_add_tail( &acquired_device_list, &impl->entry ); - LeaveCriticalSection( &dinput_hook_crit ); - - SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); -} - -void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) -{ - struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - - EnterCriticalSection( &dinput_hook_crit ); - list_remove( &impl->entry ); - LeaveCriticalSection( &dinput_hook_crit ); - - SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); -} - static void unhook_device_window_foreground_changes( struct dinput_device *device ) { if (!device->cbt_hook) return; @@ -429,37 +407,67 @@ static DWORD WINAPI dinput_thread_proc( void *params ) return 0; } -void input_thread_add_user(void) +void input_thread_start(void) { + HANDLE start_event; + + TRACE( "Starting input thread.\n" ); + + if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) + ERR( "Failed to create start event, error %lu\n", GetLastError() ); + else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, NULL ))) + ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); + else + WaitForSingleObject( start_event, INFINITE ); + + CloseHandle( start_event ); +} + +void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) +{ + struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); + EnterCriticalSection( &dinput_hook_crit ); - if (!input_thread_user_count++) - { - HANDLE start_event; + /* start the input thread now if it wasn't started already */ + if (!dinput_thread) input_thread_start(); + list_add_tail( &acquired_device_list, &impl->entry ); + LeaveCriticalSection( &dinput_hook_crit ); - TRACE( "Starting input thread.\n" ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); +} - if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) - ERR( "Failed to create start event, error %lu\n", GetLastError() ); - else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, NULL ))) - ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); - else - WaitForSingleObject( start_event, INFINITE ); +void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) +{ + struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - CloseHandle( start_event ); - } + EnterCriticalSection( &dinput_hook_crit ); + list_remove( &impl->entry ); + LeaveCriticalSection( &dinput_hook_crit ); + + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); +} + +void input_thread_add_user(void) +{ + /* we cannot start the input thread here because some games create dinput objects from their DllMain, and + * starting the thread will wait for it to initialize, which requires the loader lock to be released. + */ + EnterCriticalSection( &dinput_hook_crit ); + input_thread_user_count++; LeaveCriticalSection( &dinput_hook_crit ); } void input_thread_remove_user(void) { EnterCriticalSection( &dinput_hook_crit ); - if (!--input_thread_user_count) + if (!--input_thread_user_count && dinput_thread) { TRACE( "Stopping input thread.\n" ); SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_THREAD_STOP, 0 ); WaitForSingleObject( dinput_thread, INFINITE ); CloseHandle( dinput_thread ); + dinput_thread = NULL; } LeaveCriticalSection( &dinput_hook_crit ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2872
participants (1)
-
Rémi Bernon