]> Repos - portaudio/commitdiff
refactored COM initialization for dsound, asio and wasapi to new source file pa_win_c...
authorrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 9 May 2011 20:05:34 +0000 (20:05 +0000)
committerrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 9 May 2011 20:05:34 +0000 (20:05 +0000)
src/hostapi/asio/pa_asio.cpp
src/hostapi/dsound/pa_win_ds.c
src/hostapi/wasapi/pa_win_wasapi.c
src/os/win/pa_win_coinitialize.c [new file with mode: 0644]
src/os/win/pa_win_coinitialize.h [new file with mode: 0644]

index 19f7a2103bfb91d93208a98ae804ec5a9e0153a6..ff3b180cf0a0bdcaa06b16ca8e3b870d2d5a5da4 100644 (file)
 #include "pa_debugprint.h"
 #include "pa_ringbuffer.h"
 
+#include "pa_win_coinitialize.h"
+
 /* This version of pa_asio.cpp is currently only targetted at Win32,
    It would require a few tweaks to work with pre-OS X Macintosh.
    To make configuration easier, we define WIN32 here to make sure
@@ -289,6 +291,8 @@ typedef struct
 
     PaUtilAllocationGroup *allocations;
 
+    PaWinUtilComInitializationResult comInitializationResult;
+
     AsioDrivers *asioDrivers;
     void *systemSpecific;
     
@@ -935,12 +939,10 @@ PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device,
 }
 
 /* Unload whatever we loaded in LoadAsioDriver().
-   Also balance the call to CoInitialize(0).
 */
 static void UnloadAsioDriver( void )
 {
        ASIOExit();
-       CoUninitialize();
 }
 
 /*
@@ -956,23 +958,8 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c
     ASIOError asioError;
     int asioIsInitialized = 0;
 
-    /* 
-       ASIO uses CoCreateInstance() to load a driver. That requires that
-       CoInitialize(0) be called for every thread that loads a driver.
-       It is OK to call CoInitialize(0) multiple times form one thread as long
-       as it is balanced by a call to CoUninitialize(). See UnloadAsioDriver().
-
-       The V18 version called CoInitialize() starting on 2/19/02.
-       That was removed from PA V19 for unknown reasons.
-       Phil Burk added it back on 6/27/08 so that JSyn would work.
-    */
-       CoInitialize( 0 );
-
     if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) )
     {
-               /* If this returns an error then it might be because CoInitialize(0) was removed.
-                 It should be called right before this.
-           */
         result = paUnanticipatedHostError;
         PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
         goto error;
@@ -1021,7 +1008,7 @@ error:
        {
                ASIOExit();
        }
-       CoUninitialize();
+
     return result;
 }
 
@@ -1053,6 +1040,24 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
         goto error;
     }
 
+    /*
+        We initialize COM ourselves here and uninitialize it in Terminate().
+        This should be the only COM initialization needed in this module.
+
+        The ASIO SDK may also initialize COM but since we want to reduce dependency
+        on the ASIO SDK we manage COM initialization ourselves.
+
+        There used to be code that initialized COM in other situations
+        such as when creating a Stream. This made PA work when calling Pa_CreateStream
+        from a non-main thread. However we currently consider initialization 
+        of COM in non-main threads to be the caller's responsibility.
+    */
+    result = PaWinUtil_CoInitialize( paASIO, &asioHostApi->comInitializationResult );
+    if( result != paNoError )
+    {
+        goto error;
+    }
+
     asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
 
     asioHostApi->allocations = PaUtil_CreateAllocationGroup();
@@ -1065,7 +1070,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
     /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
     try
     {
-        asioHostApi->asioDrivers = new AsioDrivers(); /* calls CoInitialize(0) */
+        asioHostApi->asioDrivers = new AsioDrivers(); /* invokes CoInitialize(0) in AsioDriverList::AsioDriverList */
     } 
     catch (std::bad_alloc)
     {
@@ -1347,8 +1352,11 @@ error:
         delete asioHostApi->asioDrivers;
         asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
 
+        PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
+
         PaUtil_FreeMemory( asioHostApi );
     }
+
     return result;
 }
 
@@ -1368,9 +1376,11 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
         PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
     }
 
-    delete asioHostApi->asioDrivers; /* calls CoUninitialize() */
+    delete asioHostApi->asioDrivers;
     asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
 
+    PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
+
     PaUtil_FreeMemory( asioHostApi );
 }
 
@@ -3836,7 +3846,12 @@ PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
     int asioIsInitialized = 0;
     PaAsioHostApiRepresentation *asioHostApi;
     PaAsioDeviceInfo *asioDeviceInfo;
+    PaWinUtilComInitializationResult comInitializationResult;
 
+    /* initialize COM again here, we might be in another thread */
+    result = PaWinUtil_CoInitialize( paASIO, &comInitializationResult );
+    if( result != paNoError )
+        return result;
 
     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
     if( result != paNoError )
@@ -3863,9 +3878,6 @@ PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
 
     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
 
-    /* See notes about CoInitialize(0) in LoadAsioDriver(). */
-       CoInitialize(0);
-
     if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
     {
         result = paUnanticipatedHostError;
@@ -3914,7 +3926,6 @@ PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErr
         goto error;
     }
 
-       CoUninitialize();
 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
     return result;
@@ -3924,7 +3935,8 @@ error:
        {
                ASIOExit();
        }
-       CoUninitialize();
+
+    PaWinUtil_CoUninitialize( paASIO, &comInitializationResult );
 
     return result;
 }
index e99aca5f256c35e3697719f4ffe90e030737dfca..df9cad511dac3a183b7b2e951d58f19817857a52 100644 (file)
@@ -74,6 +74,7 @@
 #include "pa_win_ds_dynlink.h"
 #include "pa_win_waveformat.h"
 #include "pa_win_wdmks_utils.h"
+#include "pa_win_coinitialize.h"
 
 #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
 #pragma comment( lib, "dsound.lib" )
@@ -186,7 +187,7 @@ typedef struct
 
     /* implementation specific data goes here */
 
-    char                    comWasInitialized;
+    PaWinUtilComInitializationResult comInitializationResult;
 
 } PaWinDsHostApiRepresentation;
 
@@ -1011,32 +1012,15 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde
     int i, deviceCount;
     PaWinDsHostApiRepresentation *winDsHostApi;
     DSDeviceNamesAndGUIDs deviceNamesAndGUIDs;
-
     PaWinDsDeviceInfo *deviceInfoArray;
-    char comWasInitialized = 0;
-
-    /*
-        If COM is already initialized CoInitialize will either return
-        FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different
-        threading mode. In either case we shouldn't consider it an error
-        but we need to be careful to not call CoUninitialize() if 
-        RPC_E_CHANGED_MODE was returned.
-    */
-
-    HRESULT hr = CoInitialize(NULL);
-    if( FAILED(hr) && hr != RPC_E_CHANGED_MODE )
-        return paUnanticipatedHostError;
 
-    if( hr != RPC_E_CHANGED_MODE )
-        comWasInitialized = 1;
+    PaWinDs_InitializeDSoundEntryPoints();
 
     /* initialise guid vectors so they can be safely deleted on error */
     deviceNamesAndGUIDs.winDsHostApi = NULL;
     deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL;
     deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL;
 
-    PaWinDs_InitializeDSoundEntryPoints();
-
     winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
     if( !winDsHostApi )
     {
@@ -1044,7 +1028,11 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde
         goto error;
     }
 
-    winDsHostApi->comWasInitialized = comWasInitialized;
+    result = PaWinUtil_CoInitialize( paDirectSound, &winDsHostApi->comInitializationResult );
+    if( result != paNoError )
+    {
+        goto error;
+    }
 
     winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
     if( !winDsHostApi->allocations )
@@ -1183,15 +1171,16 @@ error:
             PaUtil_FreeAllAllocations( winDsHostApi->allocations );
             PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
         }
-                
+        
+        PaWinUtil_CoUninitialize( paDirectSound, &winDsHostApi->comInitializationResult );
+
         PaUtil_FreeMemory( winDsHostApi );
     }
 
     TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
     TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
 
-    if( comWasInitialized )
-        CoUninitialize();
+    PaWinDs_TerminateDSoundEntryPoints();
 
     return result;
 }
@@ -1201,7 +1190,6 @@ error:
 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
 {
     PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
-    char comWasInitialized = winDsHostApi->comWasInitialized;
 
     /*
         IMPLEMENT ME:
@@ -1214,12 +1202,11 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
         PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
     }
 
+    PaWinUtil_CoUninitialize( paDirectSound, &winDsHostApi->comInitializationResult );
+
     PaUtil_FreeMemory( winDsHostApi );
 
     PaWinDs_TerminateDSoundEntryPoints();
-
-    if( comWasInitialized )
-        CoUninitialize();
 }
 
 
index 4d052072f97e4a82cea9cf4c8b5172c0e360f6cb..d3824323944228d1c2d34c7801067623e857f8e3 100644 (file)
@@ -75,6 +75,8 @@
 #include "pa_debugprint.h"\r
 #include "pa_ringbuffer.h"\r
 \r
+#include "pa_win_coinitialize.h"\r
+\r
 #ifndef NTDDI_VERSION\r
  \r
     #undef WINVER\r
@@ -370,6 +372,8 @@ typedef struct
 \r
     /* implementation specific data goes here */\r
 \r
+    PaWinUtilComInitializationResult comInitializationResult;\r
+\r
     //in case we later need the synch\r
     IMMDeviceEnumerator *enumerator;\r
 \r
@@ -512,8 +516,6 @@ void *PaWasapi_ReallocateMemory(void *ptr, size_t size);
 void PaWasapi_FreeMemory(void *ptr);\r
 \r
 // Local statics\r
-static volatile BOOL  g_WasapiCOMInit    = FALSE;\r
-static volatile DWORD g_WasapiInitThread = 0;\r
 \r
 // ------------------------------------------------------------------------------------------\r
 #define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__)\r
@@ -1057,26 +1059,6 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
         return paNoError;\r
     }\r
 \r
-    /*\r
-        If COM is already initialized CoInitialize will either return\r
-        FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different\r
-        threading mode. In either case we shouldn't consider it an error\r
-        but we need to be careful to not call CoUninitialize() if\r
-        RPC_E_CHANGED_MODE was returned.\r
-    */\r
-    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
-    if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))\r
-       {\r
-               PRINT(("WASAPI: failed CoInitialize"));\r
-        return paUnanticipatedHostError;\r
-       }\r
-    if (hr != RPC_E_CHANGED_MODE)\r
-        g_WasapiCOMInit = TRUE;\r
-\r
-       // Memorize calling thread id and report warning on Uninitialize if calling thread is different\r
-       // as CoInitialize must match CoUninitialize in the same thread.\r
-       g_WasapiInitThread = GetCurrentThreadId();\r
-\r
     paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );\r
     if (paWasapi == NULL)\r
        {\r
@@ -1084,6 +1066,12 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
         goto error;\r
     }\r
 \r
+    result = PaWinUtil_CoInitialize( paWASAPI, &paWasapi->comInitializationResult );\r
+    if( result != paNoError )\r
+    {\r
+        goto error;\r
+    }\r
+\r
     paWasapi->allocations = PaUtil_CreateAllocationGroup();\r
     if (paWasapi->allocations == NULL)\r
        {\r
@@ -1454,26 +1442,12 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
         PaUtil_DestroyAllocationGroup(paWasapi->allocations);\r
     }\r
 \r
+    PaWinUtil_CoUninitialize( paWASAPI, &paWasapi->comInitializationResult );\r
+\r
     PaUtil_FreeMemory(paWasapi);\r
 \r
        // Close AVRT\r
        CloseAVRT();\r
-\r
-       // Uninit COM (checking calling thread we won't unitialize user's COM if one is calling\r
-       //             Pa_Unitialize by mistake from not initializing thread)\r
-    if (g_WasapiCOMInit)\r
-       {\r
-               DWORD calling_thread_id = GetCurrentThreadId();\r
-               if (g_WasapiInitThread != calling_thread_id)\r
-               {\r
-                       PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n",\r
-                               calling_thread_id, g_WasapiInitThread));\r
-               }\r
-               else\r
-               {\r
-                       CoUninitialize();\r
-               }\r
-       }\r
 }\r
 \r
 // ------------------------------------------------------------------------------------------\r
diff --git a/src/os/win/pa_win_coinitialize.c b/src/os/win/pa_win_coinitialize.c
new file mode 100644 (file)
index 0000000..2fea85f
--- /dev/null
@@ -0,0 +1,144 @@
+/*\r
+ * Microsoft COM initialization routines\r
+ * Copyright (c) 1999-2011 Ross Bencina, Dmitry Kostjuchenko\r
+ *\r
+ * Based on the Open Source API proposed by Ross Bencina\r
+ * Copyright (c) 1999-2011 Ross Bencina, Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+/*\r
+ * The text above constitutes the entire PortAudio license; however,\r
+ * the PortAudio community also makes the following non-binding requests:\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version. It is also\r
+ * requested that these non-binding requests be included along with the\r
+ * license above.\r
+ */\r
+\r
+/** @file\r
+ @ingroup win_src\r
+\r
+ @brief Microsoft COM initialization routines.\r
+*/\r
+\r
+#include <windows.h>\r
+#include <objbase.h>\r
+\r
+#include "portaudio.h"\r
+#include "pa_util.h"\r
+#include "pa_debugprint.h"\r
+\r
+#include "pa_win_coinitialize.h"\r
+\r
+\r
+#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */\r
+#pragma comment( lib, "ole32.lib" )\r
+#endif\r
+\r
+\r
+/* use some special bit patterns here to try to guard against uninitialized memory errors */\r
+#define PAWINUTIL_COM_INITIALIZED       (0xb38f)\r
+#define PAWINUTIL_COM_NOT_INITIALIZED   (0xf1cd)\r
+\r
+\r
+PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult )\r
+{\r
+    HRESULT hr;\r
+\r
+    comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED;\r
+\r
+    /*\r
+        If COM is already initialized CoInitialize will either return\r
+        FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different\r
+        threading mode. In either case we shouldn't consider it an error\r
+        but we need to be careful to not call CoUninitialize() if \r
+        RPC_E_CHANGED_MODE was returned.\r
+    */\r
+\r
+    hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */\r
+    if( FAILED(hr) && hr != RPC_E_CHANGED_MODE )\r
+    {\r
+        PA_DEBUG(("CoInitializeEx failed. hr=%d\n", hr));\r
+\r
+        if( hr == E_OUTOFMEMORY )\r
+            return paInsufficientMemory;\r
+\r
+        {\r
+            char *lpMsgBuf;\r
+            FormatMessage(\r
+                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,\r
+                NULL,\r
+                hr,\r
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
+                (LPTSTR) &lpMsgBuf,\r
+                0,\r
+                NULL\r
+            );\r
+            PaUtil_SetLastHostErrorInfo( hostApiType, hr, lpMsgBuf );\r
+            LocalFree( lpMsgBuf );\r
+        }\r
+\r
+        return paUnanticipatedHostError;\r
+    }\r
+\r
+    if( hr != RPC_E_CHANGED_MODE )\r
+    {\r
+        comInitializationResult->state = PAWINUTIL_COM_INITIALIZED;\r
+\r
+        /*\r
+            Memorize calling thread id and report warning on Uninitialize if \r
+            calling thread is different as CoInitialize must match CoUninitialize \r
+            in the same thread.\r
+        */\r
+        comInitializationResult->initializingThreadId = GetCurrentThreadId();\r
+    }\r
+\r
+    return paNoError;\r
+}\r
+\r
+\r
+void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult )\r
+{\r
+    if( comInitializationResult->state != PAWINUTIL_COM_NOT_INITIALIZED\r
+            && comInitializationResult->state != PAWINUTIL_COM_INITIALIZED ){\r
+    \r
+        PA_DEBUG(("ERROR: PaWinUtil_CoUninitialize called without calling PaWinUtil_CoInitialize\n"));\r
+    }\r
+\r
+    if( comInitializationResult->state == PAWINUTIL_COM_INITIALIZED )\r
+    {\r
+        DWORD currentThreadId = GetCurrentThreadId();\r
+               if( comInitializationResult->initializingThreadId != currentThreadId )\r
+               {\r
+                       PA_DEBUG(("ERROR: failed PaWinUtil_CoUninitialize calling thread[%d] does not match initializing thread[%d]\n",\r
+                               currentThreadId, comInitializationResult->initializingThreadId));\r
+               }\r
+               else\r
+               {\r
+                       CoUninitialize();\r
+\r
+            comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED;\r
+               }\r
+    }\r
+}
\ No newline at end of file
diff --git a/src/os/win/pa_win_coinitialize.h b/src/os/win/pa_win_coinitialize.h
new file mode 100644 (file)
index 0000000..a76337c
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+ * Microsoft COM initialization routines\r
+ * Copyright (c) 1999-2011 Ross Bencina, Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+/*\r
+ * The text above constitutes the entire PortAudio license; however, \r
+ * the PortAudio community also makes the following non-binding requests:\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version. It is also \r
+ * requested that these non-binding requests be included along with the \r
+ * license above.\r
+ */\r
+\r
+/** @file\r
+ @ingroup win_src\r
+\r
+ @brief Microsoft COM initialization routines.\r
+*/\r
+\r
+#ifndef PA_WIN_COINITIALIZE_H\r
+#define PA_WIN_COINITIALIZE_H\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+\r
+/**\r
+ @brief Data type used to hold the result of an attempt to initialize COM\r
+    using PaWinUtil_CoInitialize. Must be retained between a call to \r
+    PaWinUtil_CoInitialize and a matching call to PaWinUtil_CoUninitialize.\r
+*/\r
+typedef struct PaWinUtilComInitializationResult{\r
+    int state;\r
+    int initializingThreadId;\r
+} PaWinUtilComInitializationResult;\r
+\r
+\r
+/**\r
+ @brief Initialize Microsoft COM subsystem on the current thread.\r
+\r
+ @param hostApiType the host API type id of the caller. Used for error reporting.\r
+\r
+ @param comInitializationResult An output parameter. The value pointed to by \r
+        this parameter stores information required by PaWinUtil_CoUninitialize \r
+        to correctly uninitialize COM. The value should be retained and later \r
+        passed to PaWinUtil_CoUninitialize.\r
+\r
+ If PaWinUtil_CoInitialize returns paNoError, the caller must later call\r
+ PaWinUtil_CoUninitialize once.\r
+*/\r
+PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult );\r
+\r
+\r
+/**\r
+ @brief Uninitialize the Microsoft COM subsystem on the current thread using \r
+ the result of a previous call to PaWinUtil_CoInitialize. Must be called on the same\r
+ thread as PaWinUtil_CoInitialize.\r
+\r
+ @param hostApiType the host API type id of the caller. Used for error reporting.\r
+\r
+ @param comInitializationResult An input parameter. A pointer to a value previously\r
+ initialized by a call to PaWinUtil_CoInitialize.\r
+*/\r
+void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult );\r
+\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* PA_WIN_COINITIALIZE_H */\r