refactored COM initialization for dsound, asio and wasapi to new source file pa_win_coinitialize.c. fixes com uninitialisation bugs in error cases. resolves ticket #128
This commit is contained in:
parent
cbd24dc45c
commit
52ab9d6600
5 changed files with 301 additions and 90 deletions
|
|
@ -101,6 +101,8 @@
|
|||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@
|
|||
#include "pa_debugprint.h"
|
||||
#include "pa_ringbuffer.h"
|
||||
|
||||
#include "pa_win_coinitialize.h"
|
||||
|
||||
#ifndef NTDDI_VERSION
|
||||
|
||||
#undef WINVER
|
||||
|
|
@ -370,6 +372,8 @@ typedef struct
|
|||
|
||||
/* implementation specific data goes here */
|
||||
|
||||
PaWinUtilComInitializationResult comInitializationResult;
|
||||
|
||||
//in case we later need the synch
|
||||
IMMDeviceEnumerator *enumerator;
|
||||
|
||||
|
|
@ -512,8 +516,6 @@ void *PaWasapi_ReallocateMemory(void *ptr, size_t size);
|
|||
void PaWasapi_FreeMemory(void *ptr);
|
||||
|
||||
// Local statics
|
||||
static volatile BOOL g_WasapiCOMInit = FALSE;
|
||||
static volatile DWORD g_WasapiInitThread = 0;
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
#define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
|
@ -1057,26 +1059,6 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
return paNoError;
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))
|
||||
{
|
||||
PRINT(("WASAPI: failed CoInitialize"));
|
||||
return paUnanticipatedHostError;
|
||||
}
|
||||
if (hr != RPC_E_CHANGED_MODE)
|
||||
g_WasapiCOMInit = TRUE;
|
||||
|
||||
// Memorize calling thread id and report warning on Uninitialize if calling thread is different
|
||||
// as CoInitialize must match CoUninitialize in the same thread.
|
||||
g_WasapiInitThread = GetCurrentThreadId();
|
||||
|
||||
paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );
|
||||
if (paWasapi == NULL)
|
||||
{
|
||||
|
|
@ -1084,6 +1066,12 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
goto error;
|
||||
}
|
||||
|
||||
result = PaWinUtil_CoInitialize( paWASAPI, &paWasapi->comInitializationResult );
|
||||
if( result != paNoError )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
paWasapi->allocations = PaUtil_CreateAllocationGroup();
|
||||
if (paWasapi->allocations == NULL)
|
||||
{
|
||||
|
|
@ -1454,26 +1442,12 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
|
|||
PaUtil_DestroyAllocationGroup(paWasapi->allocations);
|
||||
}
|
||||
|
||||
PaWinUtil_CoUninitialize( paWASAPI, &paWasapi->comInitializationResult );
|
||||
|
||||
PaUtil_FreeMemory(paWasapi);
|
||||
|
||||
// Close AVRT
|
||||
CloseAVRT();
|
||||
|
||||
// Uninit COM (checking calling thread we won't unitialize user's COM if one is calling
|
||||
// Pa_Unitialize by mistake from not initializing thread)
|
||||
if (g_WasapiCOMInit)
|
||||
{
|
||||
DWORD calling_thread_id = GetCurrentThreadId();
|
||||
if (g_WasapiInitThread != calling_thread_id)
|
||||
{
|
||||
PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n",
|
||||
calling_thread_id, g_WasapiInitThread));
|
||||
}
|
||||
else
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
144
src/os/win/pa_win_coinitialize.c
Normal file
144
src/os/win/pa_win_coinitialize.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Microsoft COM initialization routines
|
||||
* Copyright (c) 1999-2011 Ross Bencina, Dmitry Kostjuchenko
|
||||
*
|
||||
* Based on the Open Source API proposed by Ross Bencina
|
||||
* Copyright (c) 1999-2011 Ross Bencina, Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
@ingroup win_src
|
||||
|
||||
@brief Microsoft COM initialization routines.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#include "portaudio.h"
|
||||
#include "pa_util.h"
|
||||
#include "pa_debugprint.h"
|
||||
|
||||
#include "pa_win_coinitialize.h"
|
||||
|
||||
|
||||
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */
|
||||
#pragma comment( lib, "ole32.lib" )
|
||||
#endif
|
||||
|
||||
|
||||
/* use some special bit patterns here to try to guard against uninitialized memory errors */
|
||||
#define PAWINUTIL_COM_INITIALIZED (0xb38f)
|
||||
#define PAWINUTIL_COM_NOT_INITIALIZED (0xf1cd)
|
||||
|
||||
|
||||
PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult )
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED;
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */
|
||||
if( FAILED(hr) && hr != RPC_E_CHANGED_MODE )
|
||||
{
|
||||
PA_DEBUG(("CoInitializeEx failed. hr=%d\n", hr));
|
||||
|
||||
if( hr == E_OUTOFMEMORY )
|
||||
return paInsufficientMemory;
|
||||
|
||||
{
|
||||
char *lpMsgBuf;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
hr,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
PaUtil_SetLastHostErrorInfo( hostApiType, hr, lpMsgBuf );
|
||||
LocalFree( lpMsgBuf );
|
||||
}
|
||||
|
||||
return paUnanticipatedHostError;
|
||||
}
|
||||
|
||||
if( hr != RPC_E_CHANGED_MODE )
|
||||
{
|
||||
comInitializationResult->state = PAWINUTIL_COM_INITIALIZED;
|
||||
|
||||
/*
|
||||
Memorize calling thread id and report warning on Uninitialize if
|
||||
calling thread is different as CoInitialize must match CoUninitialize
|
||||
in the same thread.
|
||||
*/
|
||||
comInitializationResult->initializingThreadId = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
|
||||
void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult )
|
||||
{
|
||||
if( comInitializationResult->state != PAWINUTIL_COM_NOT_INITIALIZED
|
||||
&& comInitializationResult->state != PAWINUTIL_COM_INITIALIZED ){
|
||||
|
||||
PA_DEBUG(("ERROR: PaWinUtil_CoUninitialize called without calling PaWinUtil_CoInitialize\n"));
|
||||
}
|
||||
|
||||
if( comInitializationResult->state == PAWINUTIL_COM_INITIALIZED )
|
||||
{
|
||||
DWORD currentThreadId = GetCurrentThreadId();
|
||||
if( comInitializationResult->initializingThreadId != currentThreadId )
|
||||
{
|
||||
PA_DEBUG(("ERROR: failed PaWinUtil_CoUninitialize calling thread[%d] does not match initializing thread[%d]\n",
|
||||
currentThreadId, comInitializationResult->initializingThreadId));
|
||||
}
|
||||
else
|
||||
{
|
||||
CoUninitialize();
|
||||
|
||||
comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/os/win/pa_win_coinitialize.h
Normal file
94
src/os/win/pa_win_coinitialize.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Microsoft COM initialization routines
|
||||
* Copyright (c) 1999-2011 Ross Bencina, Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
@ingroup win_src
|
||||
|
||||
@brief Microsoft COM initialization routines.
|
||||
*/
|
||||
|
||||
#ifndef PA_WIN_COINITIALIZE_H
|
||||
#define PA_WIN_COINITIALIZE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
/**
|
||||
@brief Data type used to hold the result of an attempt to initialize COM
|
||||
using PaWinUtil_CoInitialize. Must be retained between a call to
|
||||
PaWinUtil_CoInitialize and a matching call to PaWinUtil_CoUninitialize.
|
||||
*/
|
||||
typedef struct PaWinUtilComInitializationResult{
|
||||
int state;
|
||||
int initializingThreadId;
|
||||
} PaWinUtilComInitializationResult;
|
||||
|
||||
|
||||
/**
|
||||
@brief Initialize Microsoft COM subsystem on the current thread.
|
||||
|
||||
@param hostApiType the host API type id of the caller. Used for error reporting.
|
||||
|
||||
@param comInitializationResult An output parameter. The value pointed to by
|
||||
this parameter stores information required by PaWinUtil_CoUninitialize
|
||||
to correctly uninitialize COM. The value should be retained and later
|
||||
passed to PaWinUtil_CoUninitialize.
|
||||
|
||||
If PaWinUtil_CoInitialize returns paNoError, the caller must later call
|
||||
PaWinUtil_CoUninitialize once.
|
||||
*/
|
||||
PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult );
|
||||
|
||||
|
||||
/**
|
||||
@brief Uninitialize the Microsoft COM subsystem on the current thread using
|
||||
the result of a previous call to PaWinUtil_CoInitialize. Must be called on the same
|
||||
thread as PaWinUtil_CoInitialize.
|
||||
|
||||
@param hostApiType the host API type id of the caller. Used for error reporting.
|
||||
|
||||
@param comInitializationResult An input parameter. A pointer to a value previously
|
||||
initialized by a call to PaWinUtil_CoInitialize.
|
||||
*/
|
||||
void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* PA_WIN_COINITIALIZE_H */
|
||||
Loading…
Reference in a new issue