CoInitialize/Uninitialize is used inconsistently in Win32 implementations
According to comments in pa_win_ds we shouldn't be calling CoUninitialize under some conditions. pa_asio (for example) doesn't follow the rules. We should probably move COM initialization to global functions in pa_win_util.c and call them from all implementations. pa_win_ds.c says:
/*
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;
/*
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;
Leave a comment
review of current status:
pa_asio.cpp just calls CoInitialize(0) without checking for errors. call is are made withenver an ASIO driver is loaded. Uninitialization ignores result of CoInitialize.
pa_win_ds.c checks error results of CoInitialize(0). call is made during host API initialization. doesn't call CoUninitialize() if the result is RPC_E_CHANGED_MODE
pa_win_wasapi.c calls CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) (same thing as CoInitialize) during host API initialization. It doesn't call CoUninitialize() if the result is RPC_E_CHANGED_MODE
COM documentation implies that CoUninitialize should only be called with CoInitialize() succeeds. It's not clear how this is supposed to work with CoInitialize returns RPC_E_CHANGED_MODE
A comment posted here (doc for CoInitializeEx()):
http://msdn.microsoft.com/en-us/library/ms695279(VS.85).aspx
says: "Call CoUninitialize() if S_OK or S_FALSE is returned. Do not if any other error including RPC_E_CHANGED_MODE is returned."
pa_asio.cpp just calls CoInitialize(0) without checking for errors. call is are made withenver an ASIO driver is loaded. Uninitialization ignores result of CoInitialize.
pa_win_ds.c checks error results of CoInitialize(0). call is made during host API initialization. doesn't call CoUninitialize() if the result is RPC_E_CHANGED_MODE
pa_win_wasapi.c calls CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) (same thing as CoInitialize) during host API initialization. It doesn't call CoUninitialize() if the result is RPC_E_CHANGED_MODE
COM documentation implies that CoUninitialize should only be called with CoInitialize() succeeds. It's not clear how this is supposed to work with CoInitialize returns RPC_E_CHANGED_MODE
A comment posted here (doc for CoInitializeEx()):
http://msdn.microsoft.com/en-us/library/ms695279(VS.85).aspx
says: "Call CoUninitialize() if S_OK or S_FALSE is returned. Do not if any other error including RPC_E_CHANGED_MODE is returned."
r1679 resolves this:
Factored routines for COM initialisation out into a separate module. This fixes some bugs with ASIO COM uninitialization in corner cases and generally cleans things up.
This change introduces a new source file pa_win_coinitialize.c Until the build files are updated you'll need to manually add this to your projects.
Note that the changes may break existing code if PA/ASIO is called from multiple threads without initializing COM. PA requires that you initialize COM yourself on other threads if you call PA functions from a thread other than the one that called Pa_Initialize().
Is someone else able to handle this for the MSVC projects (Robert?) and configure/Makefile (?)
The following host APIs use these routines: DirectSound, ASIO, WASAPI
Factored routines for COM initialisation out into a separate module. This fixes some bugs with ASIO COM uninitialization in corner cases and generally cleans things up.
This change introduces a new source file pa_win_coinitialize.c Until the build files are updated you'll need to manually add this to your projects.
Note that the changes may break existing code if PA/ASIO is called from multiple threads without initializing COM. PA requires that you initialize COM yourself on other threads if you call PA functions from a thread other than the one that called Pa_Initialize().
Is someone else able to handle this for the MSVC projects (Robert?) and configure/Makefile (?)
The following host APIs use these routines: DirectSound, ASIO, WASAPI