From a813b86c859fa75102988a3cbd0e072c8eaf6e91 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
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 baf7ed2165433..fb3b942d3206d 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 b8b27e5ced878..fa82be15775e8 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 54f3f2c96c72a..882ce33dfb945 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 c6712600f8dc1..70115fb05f7f3 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,