# SDL: Fixed crash if a broken EZFRD64.DLL is installed

**URL:** <https://discourse.libsdl.org/t/sdl-fixed-crash-if-a-broken-ezfrd64-dll-is-installed/69325>\
**Category:** SDL Commits\
**Created:** [September 15, 2026, 11:43pm UTC](https://discourse.libsdl.org/t/sdl-fixed-crash-if-a-broken-ezfrd64-dll-is-installed/69325 "2026-09-15T23:43:09Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![SDLPushPostBot](https://discourse.libsdl.org/user_avatar/discourse.libsdl.org/sdlpushpostbot/32/4370_2.png) [@SDLPushPostBot](https://discourse.libsdl.org/u/SDLPushPostBot)\
**Post date:** [September 15, 2026, 11:43pm UTC](https://discourse.libsdl.org/t/sdl-fixed-crash-if-a-broken-ezfrd64-dll-is-installed/69325/1 "2026-09-15T23:43:10Z")

</div>

> <https://github.com/libsdl-org/SDL/commit/a813b86c859fa75102988a3cbd0e072c8eaf6e91>
>
> It turns out GameInput crashes the same way as DirectInput

```diff
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,

```
