Fixed crashes in new joystick code
authorSam Lantinga
Wed, 28 Nov 2012 11:52:38 -0800
changeset 671205f046f5886b
parent 6711 e6355923901d
child 6713 fa17a97389ed
Fixed crashes in new joystick code
src/joystick/SDL_joystick.c
src/joystick/windows/SDL_dxjoystick.c
     1.1 --- a/src/joystick/SDL_joystick.c	Tue Nov 27 21:40:46 2012 -0800
     1.2 +++ b/src/joystick/SDL_joystick.c	Wed Nov 28 11:52:38 2012 -0800
     1.3 @@ -30,7 +30,8 @@
     1.4  #include "../events/SDL_events_c.h"
     1.5  #endif
     1.6  
     1.7 -SDL_Joystick *SDL_joysticks = NULL;
     1.8 +static SDL_Joystick *SDL_joysticks = NULL;
     1.9 +static SDL_Joystick *SDL_updating_joystick = NULL;
    1.10  
    1.11  int
    1.12  SDL_JoystickInit(void)
    1.13 @@ -386,6 +387,10 @@
    1.14          return;
    1.15      }
    1.16  
    1.17 +    if (joystick == SDL_updating_joystick) {
    1.18 +        return;
    1.19 +    }
    1.20 +
    1.21      SDL_SYS_JoystickClose(joystick);
    1.22  	
    1.23  	joysticklist = SDL_joysticks;
    1.24 @@ -432,6 +437,9 @@
    1.25  void
    1.26  SDL_JoystickQuit(void)
    1.27  {
    1.28 +    /* Make sure we're not getting called in the middle of updating joysticks */
    1.29 +    SDL_assert(!SDL_updating_joystick);
    1.30 +
    1.31      /* Stop the event polling */
    1.32  	while ( SDL_joysticks )
    1.33  	{
    1.34 @@ -588,6 +596,8 @@
    1.35  		 */
    1.36  		joysticknext = joystick->next;
    1.37  
    1.38 +        SDL_updating_joystick = joystick;
    1.39 +
    1.40          SDL_SYS_JoystickUpdate( joystick );
    1.41  
    1.42  		if ( joystick->closed && joystick->uncentered )
    1.43 @@ -595,7 +605,7 @@
    1.44  			int i;
    1.45  			joystick->uncentered = 0;
    1.46  
    1.47 -            // Tell the app that everything is centered/unpressed... 
    1.48 +            /* Tell the app that everything is centered/unpressed...  */
    1.49              for (i = 0; i < joystick->naxes; i++)
    1.50                  SDL_PrivateJoystickAxis(joystick, i, 0);
    1.51  
    1.52 @@ -604,8 +614,16 @@
    1.53  
    1.54              for (i = 0; i < joystick->nhats; i++)
    1.55                  SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
    1.56 +
    1.57  		}
    1.58  
    1.59 +        SDL_updating_joystick = NULL;
    1.60 +
    1.61 +        /* If the joystick was closed while updating, free it here */
    1.62 +        if ( joystick->ref_count <= 0 ) {
    1.63 +            SDL_JoystickClose(joystick);
    1.64 +        }
    1.65 +
    1.66  		joystick = joysticknext;
    1.67  	}
    1.68  
     2.1 --- a/src/joystick/windows/SDL_dxjoystick.c	Tue Nov 27 21:40:46 2012 -0800
     2.2 +++ b/src/joystick/windows/SDL_dxjoystick.c	Wed Nov 28 11:52:38 2012 -0800
     2.3 @@ -498,24 +498,6 @@
     2.4  }
     2.5  
     2.6  
     2.7 -/*  helper func to create a hidden, message only window for the joystick detect thread
     2.8 - */
     2.9 -HWND CreateHiddenJoystickDetectWindow() {
    2.10 -	WNDCLASSEX wincl;
    2.11 -	HWND hMessageWindow = 0;
    2.12 -	SDL_memset( &wincl, 0x0, sizeof(wincl) );
    2.13 -	wincl.hInstance = GetModuleHandle( NULL );
    2.14 -	wincl.lpszClassName = L"Message";
    2.15 -	wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      // This function is called by windows
    2.16 -	wincl.cbSize = sizeof (WNDCLASSEX);
    2.17 -
    2.18 -	if (!RegisterClassEx (&wincl))
    2.19 -		return 0;
    2.20 -
    2.21 -	hMessageWindow = (HWND)CreateWindowEx( 0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
    2.22 -	return hMessageWindow;
    2.23 -}
    2.24 -
    2.25  DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
    2.26  	0xC0, 0x4F, 0xB9, 0x51, 0xED);
    2.27  
    2.28 @@ -529,12 +511,26 @@
    2.29  	HDEVNOTIFY hNotify = 0;
    2.30  	DEV_BROADCAST_DEVICEINTERFACE dbh;
    2.31  	SDL_bool bOpenedXInputDevices[4];
    2.32 +	WNDCLASSEX wincl;
    2.33  
    2.34  	SDL_memset( bOpenedXInputDevices, 0x0, sizeof(bOpenedXInputDevices) );
    2.35  
    2.36  	result = WIN_CoInitialize();
    2.37  
    2.38 -	messageWindow = CreateHiddenJoystickDetectWindow();
    2.39 +	SDL_memset( &wincl, 0x0, sizeof(wincl) );
    2.40 +	wincl.hInstance = GetModuleHandle( NULL );
    2.41 +	wincl.lpszClassName = L"Message";
    2.42 +	wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      // This function is called by windows
    2.43 +	wincl.cbSize = sizeof (WNDCLASSEX);
    2.44 +
    2.45 +	if (!RegisterClassEx (&wincl))
    2.46 +	{		
    2.47 +		SDL_SetError("Failed to create register class for joystick autodetect.",
    2.48 +		GetLastError());
    2.49 +		return -1;
    2.50 +	}
    2.51 +
    2.52 +	messageWindow = (HWND)CreateWindowEx( 0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
    2.53  	if ( !messageWindow )
    2.54  	{
    2.55  		SDL_SetError("Failed to create message window for joystick autodetect.",
    2.56 @@ -611,6 +607,8 @@
    2.57  
    2.58  	if ( messageWindow )
    2.59  		DestroyWindow( messageWindow );
    2.60 +
    2.61 +	UnregisterClass( wincl.lpszClassName, wincl.hInstance );
    2.62  	messageWindow = 0;
    2.63  	WIN_CoUninitialize();
    2.64  	return 1;
    2.65 @@ -720,22 +718,25 @@
    2.66  	EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
    2.67  {
    2.68  	JoyStick_DeviceData *pNewJoystick;
    2.69 +	JoyStick_DeviceData *pPrevJoystick = NULL;
    2.70  	SDL_bool bXInputDevice;
    2.71  	pNewJoystick = *(JoyStick_DeviceData **)pContext;
    2.72  	while ( pNewJoystick )
    2.73  	{
    2.74  		if ( !SDL_memcmp( &pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance) ) )
    2.75  		{
    2.76 -			if ( SYS_Joystick )
    2.77 -			{
    2.78 -				pNewJoystick->pNext = SYS_Joystick;
    2.79 -			}
    2.80 -			SYS_Joystick = pNewJoystick;
    2.81  			/* if we are replacing the front of the list then update it */
    2.82  			if ( pNewJoystick == *(JoyStick_DeviceData **)pContext ) 
    2.83  			{
    2.84  				*(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
    2.85  			}
    2.86 +			else if ( pPrevJoystick )
    2.87 +			{
    2.88 +				pPrevJoystick->pNext = pNewJoystick->pNext;
    2.89 +			}
    2.90 +
    2.91 +			pNewJoystick->pNext = SYS_Joystick;
    2.92 +			SYS_Joystick = pNewJoystick;
    2.93  
    2.94  			s_pKnownJoystickGUIDs[ s_iNewGUID ] = pdidInstance->guidInstance;
    2.95  			s_iNewGUID++;
    2.96 @@ -745,6 +746,7 @@
    2.97  				return DIENUM_STOP; 
    2.98  		}
    2.99  
   2.100 +		pPrevJoystick = pNewJoystick;
   2.101  		pNewJoystick = pNewJoystick->pNext;
   2.102  	}
   2.103  
   2.104 @@ -756,17 +758,17 @@
   2.105  
   2.106  	if ( bXInputDevice )
   2.107  	{
   2.108 -		SDL_memset(&(pNewJoystick->dxdevice), 0x0,
   2.109 -			sizeof(DIDEVICEINSTANCE));
   2.110  		pNewJoystick->bXInputDevice = SDL_TRUE;
   2.111  		pNewJoystick->XInputUserId = INVALID_XINPUT_USERID;
   2.112  	}
   2.113  	else
   2.114  	{
   2.115  		pNewJoystick->bXInputDevice = SDL_FALSE;
   2.116 -		SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
   2.117 -			sizeof(DIDEVICEINSTANCE));
   2.118  	}
   2.119 +	
   2.120 +	SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
   2.121 +		sizeof(DIDEVICEINSTANCE));
   2.122 +
   2.123  	pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
   2.124  	pNewJoystick->send_add_event = 1;
   2.125  	pNewJoystick->nInstanceID = ++s_nInstanceID;