pa_win_coinitialize.c (5230B)
1 /* 2 * Microsoft COM initialization routines 3 * Copyright (c) 1999-2011 Ross Bencina, Dmitry Kostjuchenko 4 * 5 * Based on the Open Source API proposed by Ross Bencina 6 * Copyright (c) 1999-2011 Ross Bencina, Phil Burk 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files 10 * (the "Software"), to deal in the Software without restriction, 11 * including without limitation the rights to use, copy, modify, merge, 12 * publish, distribute, sublicense, and/or sell copies of the Software, 13 * and to permit persons to whom the Software is furnished to do so, 14 * subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 /* 29 * The text above constitutes the entire PortAudio license; however, 30 * the PortAudio community also makes the following non-binding requests: 31 * 32 * Any person wishing to distribute modifications to the Software is 33 * requested to send the modifications to the original developer so that 34 * they can be incorporated into the canonical version. It is also 35 * requested that these non-binding requests be included along with the 36 * license above. 37 */ 38 39 /** @file 40 @ingroup win_src 41 42 @brief Microsoft COM initialization routines. 43 */ 44 45 #include <windows.h> 46 #include <objbase.h> 47 48 #include "portaudio.h" 49 #include "pa_util.h" 50 #include "pa_debugprint.h" 51 52 #include "pa_win_coinitialize.h" 53 54 55 #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) /* MSC version 6 and above */ 56 #pragma comment( lib, "ole32.lib" ) 57 #endif 58 59 60 /* use some special bit patterns here to try to guard against uninitialized memory errors */ 61 #define PAWINUTIL_COM_INITIALIZED (0xb38f) 62 #define PAWINUTIL_COM_NOT_INITIALIZED (0xf1cd) 63 64 65 PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ) 66 { 67 HRESULT hr; 68 69 comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED; 70 71 /* 72 If COM is already initialized CoInitialize will either return 73 FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different 74 threading mode. In either case we shouldn't consider it an error 75 but we need to be careful to not call CoUninitialize() if 76 RPC_E_CHANGED_MODE was returned. 77 */ 78 79 #if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) 80 hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */ 81 #else 82 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 83 #endif 84 if( FAILED(hr) && hr != RPC_E_CHANGED_MODE ) 85 { 86 PA_DEBUG(("CoInitialize(0) failed. hr=%d\n", hr)); 87 88 if( hr == E_OUTOFMEMORY ) 89 return paInsufficientMemory; 90 91 { 92 char *lpMsgBuf; 93 FormatMessage( 94 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 95 NULL, 96 hr, 97 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 98 (LPTSTR) &lpMsgBuf, 99 0, 100 NULL 101 ); 102 PaUtil_SetLastHostErrorInfo( hostApiType, hr, lpMsgBuf ); 103 LocalFree( lpMsgBuf ); 104 } 105 106 return paUnanticipatedHostError; 107 } 108 109 if( hr != RPC_E_CHANGED_MODE ) 110 { 111 comInitializationResult->state = PAWINUTIL_COM_INITIALIZED; 112 113 /* 114 Memorize calling thread id and report warning on Uninitialize if 115 calling thread is different as CoInitialize must match CoUninitialize 116 in the same thread. 117 */ 118 comInitializationResult->initializingThreadId = GetCurrentThreadId(); 119 } 120 121 return paNoError; 122 } 123 124 125 void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ) 126 { 127 if( comInitializationResult->state != PAWINUTIL_COM_NOT_INITIALIZED 128 && comInitializationResult->state != PAWINUTIL_COM_INITIALIZED ){ 129 130 PA_DEBUG(("ERROR: PaWinUtil_CoUninitialize called without calling PaWinUtil_CoInitialize\n")); 131 } 132 133 if( comInitializationResult->state == PAWINUTIL_COM_INITIALIZED ) 134 { 135 DWORD currentThreadId = GetCurrentThreadId(); 136 if( comInitializationResult->initializingThreadId != currentThreadId ) 137 { 138 PA_DEBUG(("ERROR: failed PaWinUtil_CoUninitialize calling thread[%d] does not match initializing thread[%d]\n", 139 currentThreadId, comInitializationResult->initializingThreadId)); 140 } 141 else 142 { 143 CoUninitialize(); 144 145 comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED; 146 } 147 } 148 }