From 5faee44c7c9a3e4f161b406e91c2917ae7bdfc36 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 28 Nov 2012 11:52:38 -0800 Subject: [PATCH] Fixed crashes in new joystick code --- src/joystick/SDL_joystick.c | 22 +++++++++- src/joystick/windows/SDL_dxjoystick.c | 58 ++++++++++++++------------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 6baae4540..4a7c3d7b2 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -30,7 +30,8 @@ #include "../events/SDL_events_c.h" #endif -SDL_Joystick *SDL_joysticks = NULL; +static SDL_Joystick *SDL_joysticks = NULL; +static SDL_Joystick *SDL_updating_joystick = NULL; int SDL_JoystickInit(void) @@ -386,6 +387,10 @@ SDL_JoystickClose(SDL_Joystick * joystick) return; } + if (joystick == SDL_updating_joystick) { + return; + } + SDL_SYS_JoystickClose(joystick); joysticklist = SDL_joysticks; @@ -432,6 +437,9 @@ SDL_JoystickClose(SDL_Joystick * joystick) void SDL_JoystickQuit(void) { + /* Make sure we're not getting called in the middle of updating joysticks */ + SDL_assert(!SDL_updating_joystick); + /* Stop the event polling */ while ( SDL_joysticks ) { @@ -588,6 +596,8 @@ SDL_JoystickUpdate(void) */ joysticknext = joystick->next; + SDL_updating_joystick = joystick; + SDL_SYS_JoystickUpdate( joystick ); if ( joystick->closed && joystick->uncentered ) @@ -595,7 +605,7 @@ SDL_JoystickUpdate(void) int i; joystick->uncentered = 0; - // Tell the app that everything is centered/unpressed... + /* Tell the app that everything is centered/unpressed... */ for (i = 0; i < joystick->naxes; i++) SDL_PrivateJoystickAxis(joystick, i, 0); @@ -604,8 +614,16 @@ SDL_JoystickUpdate(void) for (i = 0; i < joystick->nhats; i++) SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); + } + SDL_updating_joystick = NULL; + + /* If the joystick was closed while updating, free it here */ + if ( joystick->ref_count <= 0 ) { + SDL_JoystickClose(joystick); + } + joystick = joysticknext; } diff --git a/src/joystick/windows/SDL_dxjoystick.c b/src/joystick/windows/SDL_dxjoystick.c index 8d50f2018..d7bd1c57b 100644 --- a/src/joystick/windows/SDL_dxjoystick.c +++ b/src/joystick/windows/SDL_dxjoystick.c @@ -498,24 +498,6 @@ LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM w } -/* helper func to create a hidden, message only window for the joystick detect thread - */ -HWND CreateHiddenJoystickDetectWindow() { - WNDCLASSEX wincl; - HWND hMessageWindow = 0; - SDL_memset( &wincl, 0x0, sizeof(wincl) ); - wincl.hInstance = GetModuleHandle( NULL ); - wincl.lpszClassName = L"Message"; - wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; // This function is called by windows - wincl.cbSize = sizeof (WNDCLASSEX); - - if (!RegisterClassEx (&wincl)) - return 0; - - hMessageWindow = (HWND)CreateWindowEx( 0, L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL ); - return hMessageWindow; -} - DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \ 0xC0, 0x4F, 0xB9, 0x51, 0xED); @@ -529,12 +511,26 @@ SDL_JoystickThread(void *_data) HDEVNOTIFY hNotify = 0; DEV_BROADCAST_DEVICEINTERFACE dbh; SDL_bool bOpenedXInputDevices[4]; + WNDCLASSEX wincl; SDL_memset( bOpenedXInputDevices, 0x0, sizeof(bOpenedXInputDevices) ); result = WIN_CoInitialize(); - messageWindow = CreateHiddenJoystickDetectWindow(); + SDL_memset( &wincl, 0x0, sizeof(wincl) ); + wincl.hInstance = GetModuleHandle( NULL ); + wincl.lpszClassName = L"Message"; + wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; // This function is called by windows + wincl.cbSize = sizeof (WNDCLASSEX); + + if (!RegisterClassEx (&wincl)) + { + SDL_SetError("Failed to create register class for joystick autodetect.", + GetLastError()); + return -1; + } + + messageWindow = (HWND)CreateWindowEx( 0, L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL ); if ( !messageWindow ) { SDL_SetError("Failed to create message window for joystick autodetect.", @@ -611,6 +607,8 @@ SDL_JoystickThread(void *_data) if ( messageWindow ) DestroyWindow( messageWindow ); + + UnregisterClass( wincl.lpszClassName, wincl.hInstance ); messageWindow = 0; WIN_CoUninitialize(); return 1; @@ -720,22 +718,25 @@ static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) { JoyStick_DeviceData *pNewJoystick; + JoyStick_DeviceData *pPrevJoystick = NULL; SDL_bool bXInputDevice; pNewJoystick = *(JoyStick_DeviceData **)pContext; while ( pNewJoystick ) { if ( !SDL_memcmp( &pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance) ) ) { - if ( SYS_Joystick ) - { - pNewJoystick->pNext = SYS_Joystick; - } - SYS_Joystick = pNewJoystick; /* if we are replacing the front of the list then update it */ if ( pNewJoystick == *(JoyStick_DeviceData **)pContext ) { *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext; } + else if ( pPrevJoystick ) + { + pPrevJoystick->pNext = pNewJoystick->pNext; + } + + pNewJoystick->pNext = SYS_Joystick; + SYS_Joystick = pNewJoystick; s_pKnownJoystickGUIDs[ s_iNewGUID ] = pdidInstance->guidInstance; s_iNewGUID++; @@ -745,6 +746,7 @@ static BOOL CALLBACK return DIENUM_STOP; } + pPrevJoystick = pNewJoystick; pNewJoystick = pNewJoystick->pNext; } @@ -756,17 +758,17 @@ static BOOL CALLBACK if ( bXInputDevice ) { - SDL_memset(&(pNewJoystick->dxdevice), 0x0, - sizeof(DIDEVICEINSTANCE)); pNewJoystick->bXInputDevice = SDL_TRUE; pNewJoystick->XInputUserId = INVALID_XINPUT_USERID; } else { pNewJoystick->bXInputDevice = SDL_FALSE; - SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance, - sizeof(DIDEVICEINSTANCE)); } + + SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance, + sizeof(DIDEVICEINSTANCE)); + pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName); pNewJoystick->send_add_event = 1; pNewJoystick->nInstanceID = ++s_nInstanceID;