From a813b86c859fa75102988a3cbd0e072c8eaf6e91 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 15 Sep 2026 16:39:54 -0700 Subject: [PATCH] Fixed crash if a broken EZFRD64.DLL is installed It turns out GameInput crashes the same way as DirectInput --- src/core/windows/SDL_gameinput.cpp | 4 +++ src/core/windows/SDL_windows.c | 31 +++++++++++++++++++++++ src/core/windows/SDL_windows.h | 3 +++ src/joystick/windows/SDL_dinputjoystick.c | 26 +------------------ 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/core/windows/SDL_gameinput.cpp b/src/core/windows/SDL_gameinput.cpp index baf7ed2165..fb3b942d32 100644 --- a/src/core/windows/SDL_gameinput.cpp +++ b/src/core/windows/SDL_gameinput.cpp @@ -38,6 +38,10 @@ bool SDL_InitGameInput(IGameInput **ppGameInput) return false; } + if (WIN_HasBrokenEZFRD64DLL()) { + return SDL_SetError("GameInput disabled to prevent application crashing"); + } + typedef HRESULT (WINAPI *pfnGameInputCreate)(IGameInput **gameInput); pfnGameInputCreate pGameInputCreate = (pfnGameInputCreate)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate"); if (!pGameInputCreate) { diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index b8b27e5ced..fa82be1577 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -768,4 +768,35 @@ char *WIN_GetModulePath(HMODULE handle) return retval; } +bool WIN_HasBrokenEZFRD64DLL(void) +{ + static bool checked = false; + static bool has_broken_EZFRD64_DLL = false; + +#ifdef _WIN64 + if (!checked) { + if (SDL_GetHintBoolean("SDL_CHECK_BROKEN_EZFRD64", true)) { + // The 64-bit version of EZFRD64.DLL crashes after being loaded, + // which happens implicitly when querying the device capabilities, + // so make sure we don't do that if there's a possibility of crashing + static const char *directories[] = { + "C:/Windows/USB_Vibration", + "C:/Windows/USB Vibration" + }; + for (int i = 0; i < SDL_arraysize(directories) && !has_broken_EZFRD64DLL; ++i) { + int count = 0; + char **files = SDL_GlobDirectory(directories[i], "*/EZFRD64.DLL", SDL_GLOB_CASEINSENSITIVE, &count); + if (count > 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Broken EZFRD64.DLL detected, disabling GameInput and DirectInput force feedback"); + has_broken_EZFRD64_DLL = true; + } + SDL_free(files); + } + } + checked = true; + } +#endif + return has_broken_EZFRD64_DLL; +} + #endif // defined(SDL_PLATFORM_WINDOWS) diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index 54f3f2c96c..882ce33dfb 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -218,6 +218,9 @@ extern const char *WIN_CheckDefaultArgcArgv(int *pargc, char ***pargv, void **pa // Does all the win32 tapdancing to make GetModuleFileName work. Returns a SDL_malloc'd UTF-8 string, or NULL on failure. extern char *WIN_GetModulePath(HMODULE handle); +// Return true if this system has a broken EZFRD64.DLL installed +extern bool WIN_HasBrokenEZFRD64DLL(void); + // Ends C function definitions when using C++ #ifdef __cplusplus } diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c index c6712600f8..70115fb05f 100644 --- a/src/joystick/windows/SDL_dinputjoystick.c +++ b/src/joystick/windows/SDL_dinputjoystick.c @@ -45,7 +45,6 @@ extern HWND SDL_HelperWindow; // local variables static bool coinitialized = false; static LPDIRECTINPUT8 dinput = NULL; -static bool has_broken_EZFRD64DLL = false; // Taken from Wine - Thanks! static DIOBJECTDATAFORMAT dfDIJoystick2[] = { @@ -438,29 +437,6 @@ bool SDL_DINPUT_JoystickInit(void) dinput = NULL; return SetDIerror("IDirectInput::Initialize", result); } - -#ifdef _WIN64 - if (SDL_GetHintBoolean("SDL_JOYSTICK_CHECK_EZFRD64", true)) { - // The 64-bit version of EZFRD64.DLL crashes after being loaded, - // which happens implicitly when querying the device capabilities, - // so make sure we don't do that if there's a possibility of crashing - static const char *directories[] = { - "C:/Windows/USB_Vibration", - "C:/Windows/USB Vibration" - }; - for (int i = 0; i < SDL_arraysize(directories) && !has_broken_EZFRD64DLL; ++i) { - int count = 0; - char **files = SDL_GlobDirectory(directories[i], "*/EZFRD64.DLL", SDL_GLOB_CASEINSENSITIVE, &count); - if (count > 0) { - has_broken_EZFRD64DLL = true; - } - SDL_free(files); - } - if (has_broken_EZFRD64DLL) { - SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Broken EZFRD64.DLL detected, disabling DirectInput force feedback"); - } - } -#endif return true; } @@ -806,7 +782,7 @@ bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joysti return SetDIerror("IDirectInputDevice8::SetDataFormat", result); } - if (!has_broken_EZFRD64DLL) { + if (!WIN_HasBrokenEZFRD64DLL()) { // Get device capabilities to see if we are force feedback capable result = IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,