Cleaned up CoInitialize() politics on Windows.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 03 Aug 2011 04:22:47 -0400
changeset 5591 17beb16fa838
parent 5590 db152c9f31c3
child 5592 2e88d0742f4d
Cleaned up CoInitialize() politics on Windows.
src/core/windows/SDL_windows.c
src/core/windows/SDL_windows.h
src/haptic/windows/SDL_syshaptic.c
src/joystick/windows/SDL_dxjoystick.c
src/video/windows/SDL_windowskeyboard.c
--- a/src/core/windows/SDL_windows.c	Thu Aug 04 01:07:13 2011 -0400
+++ b/src/core/windows/SDL_windows.c	Wed Aug 03 04:22:47 2011 -0400
@@ -23,6 +23,8 @@
 #include "SDL_error.h"
 #include "SDL_windows.h"
 
+#include <objbase.h>  /* for CoInitialize/CoUninitialize */
+
 
 /* Sets an error message based on GetLastError() */
 void
@@ -37,4 +39,23 @@
     SDL_free(message);
 }
 
+HRESULT
+WIN_CoInitialize(void)
+{
+    /* S_FALSE means success, but someone else already initialized. */
+    /* You still need to call CoUninitialize in this case! */
+    const HRESULT hr = CoInitialize(NULL);
+    if ((hr == S_OK) || (hr == S_FALSE)) {
+        return S_OK;
+    }
+
+    return hr;
+}
+
+void
+WIN_CoUninitialize(void)
+{
+    CoUninitialize();
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/core/windows/SDL_windows.h	Thu Aug 04 01:07:13 2011 -0400
+++ b/src/core/windows/SDL_windows.h	Wed Aug 03 04:22:47 2011 -0400
@@ -47,6 +47,10 @@
 /* Sets an error message based on GetLastError() */
 extern void WIN_SetError(const char *prefix);
 
+/* Wrap up the oddities of CoInitialize() into a common function. */
+extern HRESULT WIN_CoInitialize(void);
+extern void WIN_CoUninitialize(void);
+
 #endif /* _INCLUDED_WINDOWS_H */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/haptic/windows/SDL_syshaptic.c	Thu Aug 04 01:07:13 2011 -0400
+++ b/src/haptic/windows/SDL_syshaptic.c	Wed Aug 03 04:22:47 2011 -0400
@@ -68,6 +68,7 @@
 /*
  * Internal stuff.
  */
+static SDL_bool coinitialized = SDL_FALSE;
 static LPDIRECTINPUT dinput = NULL;
 
 
@@ -147,15 +148,18 @@
 
     SDL_numhaptics = 0;
 
-    ret = CoInitialize(NULL);
+    ret = WIN_CoInitialize();
     if (FAILED(ret)) {
         DI_SetError("Coinitialize", ret);
         return -1;
     }
 
+    coinitialized = SDL_TRUE;
+
     ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
                            &IID_IDirectInput, (LPVOID) & dinput);
     if (FAILED(ret)) {
+        SDL_SYS_HapticQuit();
         DI_SetError("CoCreateInstance", ret);
         return -1;
     }
@@ -163,12 +167,14 @@
     /* Because we used CoCreateInstance, we need to Initialize it, first. */
     instance = GetModuleHandle(NULL);
     if (instance == NULL) {
+        SDL_SYS_HapticQuit();
         SDL_SetError("GetModuleHandle() failed with error code %d.",
                      GetLastError());
         return -1;
     }
     ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
     if (FAILED(ret)) {
+        SDL_SYS_HapticQuit();
         DI_SetError("Initializing DirectInput device", ret);
         return -1;
     }
@@ -181,6 +187,7 @@
                                    DIEDFL_FORCEFEEDBACK |
                                    DIEDFL_ATTACHEDONLY);
     if (FAILED(ret)) {
+        SDL_SYS_HapticQuit();
         DI_SetError("Enumerating DirectInput devices", ret);
         return -1;
     }
@@ -664,8 +671,15 @@
         }
     }
 
-    IDirectInput_Release(dinput);
-    dinput = NULL;
+    if (dinput != NULL) {
+        IDirectInput_Release(dinput);
+        dinput = NULL;
+    }
+
+    if (coinitialized) {
+        WIN_CoUninitialize();
+        coinitialized = SDL_FALSE;
+    }
 }
 
 
--- a/src/joystick/windows/SDL_dxjoystick.c	Thu Aug 04 01:07:13 2011 -0400
+++ b/src/joystick/windows/SDL_dxjoystick.c	Wed Aug 03 04:22:47 2011 -0400
@@ -57,6 +57,7 @@
 
 
 /* local variables */
+static SDL_bool coinitialized = SDL_FALSE;
 static LPDIRECTINPUT dinput = NULL;
 extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
                                        LPDIRECTINPUT * ppDI,
@@ -284,16 +285,19 @@
 
     SYS_NumJoysticks = 0;
 
-    result = CoInitialize(NULL);
+    result = WIN_CoInitialize();
     if (FAILED(result)) {
         SetDIerror("CoInitialize", result);
         return (-1);
     }
 
+    coinitialized = SDL_TRUE;
+
     result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
                               &IID_IDirectInput, (LPVOID)&dinput);
 
     if (FAILED(result)) {
+        SDL_SYS_JoystickQuit();
         SetDIerror("CoCreateInstance", result);
         return (-1);
     }
@@ -301,6 +305,7 @@
     /* Because we used CoCreateInstance, we need to Initialize it, first. */
     instance = GetModuleHandle(NULL);
     if (instance == NULL) {
+        SDL_SYS_JoystickQuit();
         SDL_SetError("GetModuleHandle() failed with error code %d.",
                      GetLastError());
         return (-1);
@@ -308,6 +313,7 @@
     result = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
 
     if (FAILED(result)) {
+        SDL_SYS_JoystickQuit();
         SetDIerror("IDirectInput::Initialize", result);
         return (-1);
     }
@@ -802,8 +808,15 @@
         }
     }
 
-    IDirectInput_Release(dinput);
-    dinput = NULL;
+    if (dinput != NULL) {
+        IDirectInput_Release(dinput);
+        dinput = NULL;
+    }
+
+    if (coinitialized) {
+        WIN_CoUninitialize();
+        coinitialized = SDL_FALSE;
+    }
 }
 
 #endif /* SDL_JOYSTICK_DINPUT */
--- a/src/video/windows/SDL_windowskeyboard.c	Thu Aug 04 01:07:13 2011 -0400
+++ b/src/video/windows/SDL_windowskeyboard.c	Wed Aug 03 04:22:47 2011 -0400
@@ -305,7 +305,7 @@
         return;
 
     videodata->ime_hwnd_main = hwnd;
-    if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
+    if (SUCCEEDED(WIN_CoInitialize())) {
         videodata->ime_com_initialized = SDL_TRUE;
         CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (LPVOID *)&videodata->ime_threadmgr);
     }
@@ -389,7 +389,7 @@
         videodata->ime_threadmgr = 0;
     }
     if (videodata->ime_com_initialized) {
-        CoUninitialize();
+        WIN_CoUninitialize();
         videodata->ime_com_initialized = SDL_FALSE;
     }
     IME_DestroyTextures(videodata);