So we don't crash if the application unloads dinput. This can only happen if the application didn't release all dinput objects before unloading the module, which we have observed the Yakuza games to do.
From: Yuxuan Shui yshui@codeweavers.com
So we don't crash if the application unloads dinput. This can only happen if the application didn't release all dinput objects before unloading the module, which we have observed the Yakuza games to do. --- dlls/dinput/dinput_main.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 8f22b6c3057..eb38bbe4ee9 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -370,6 +370,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) struct input_thread_state state = {.running = TRUE}; struct dinput_device *device; HANDLE start_event = params; + HMODULE this_module = NULL; DWORD ret; MSG msg;
@@ -377,6 +378,10 @@ static DWORD WINAPI dinput_thread_proc( void *params )
di_em_win = CreateWindowW( L"DIEmWin", L"DIEmWin", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); input_thread_state = &state; + + if (!GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (void *)dinput_thread_proc, &this_module )) + ERR( "Failed to get a handle of dinput to keep it alive: %lu", GetLastError() ); + SetEvent( start_event );
while (state.running && (ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) @@ -417,6 +422,8 @@ static DWORD WINAPI dinput_thread_proc( void *params )
DestroyWindow( di_em_win ); di_em_win = NULL; + + if (this_module != NULL) FreeLibraryAndExitThread( this_module, 0 ); return 0; }
This looks okay but it's not the first time we have to tweak dinput internal thread because of various deadlock situations.
Hopefully this would work but there's a case where it wouldn't: if an application module releases its last DInput reference while holding the loader lock (ie: within DllMain), in this case we'll deadlock as `FreeLibraryAndExitThread` will also need the loader lock.
I'm going to assume that this isn't an issue, but if I'm proved wrong we would need another way to signal and wait for the thread's exit.
This merge request was approved by Rémi Bernon.