diff options
| author | Konstantin <const@const.me> | 2023-01-16 14:52:43 +0100 |
|---|---|---|
| committer | Konstantin <const@const.me> | 2023-01-16 14:52:43 +0100 |
| commit | 8c4603c73675958efc960fbd4bb599a2909d106a (patch) | |
| tree | 714dc6fc9a1672d5fd7f89676b97e10959662abc /Whisper/MF/mfStartup.cpp | |
| parent | 990a8d0dbaefc996244097397259e92758b15cce (diff) | |
Source codes
Diffstat (limited to 'Whisper/MF/mfStartup.cpp')
| -rw-r--r-- | Whisper/MF/mfStartup.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/Whisper/MF/mfStartup.cpp b/Whisper/MF/mfStartup.cpp new file mode 100644 index 0000000..b7ab829 --- /dev/null +++ b/Whisper/MF/mfStartup.cpp @@ -0,0 +1,128 @@ +#include "stdafx.h" +#include "mfStartup.h" +#include <atlbase.h> +#include <mfapi.h> +#pragma comment(lib, "Mfplat.lib") + +namespace +{ + struct sCoInitStatus + { + // Possible state: + // -1 is the initial state, coInitialize never called + // S_OK - CoInitializeEx succeeded, in this state the counter tracks the count of coInitialize() for the current thread + // S_FALSE - CoInitializeEx failed with RPC_E_CHANGED_MODE, or did nothing because already initialized for the current thread + // Error status - CoInitializeEx failed for some other reason + HRESULT code = -1; + uint32_t counter = 0; + }; + thread_local sCoInitStatus coInitStatus; + + static HRESULT coInitialize() + { + sCoInitStatus& cis = coInitStatus; + HRESULT hr = cis.code; + if( SUCCEEDED( hr ) ) + { + if( S_OK == hr ) + cis.counter++; + return S_FALSE; + } + + if( hr == HRESULT( -1 ) ) + { + hr = CoInitializeEx( nullptr, COINIT_MULTITHREADED ); + if( S_OK == hr ) + { + cis.counter = 1; + return cis.code = S_OK; + } + if( S_FALSE == hr || RPC_E_CHANGED_MODE == hr ) + { + return cis.code = S_FALSE; + } + cis.code = hr; + return hr; + } + + return hr; + } + + static void coUninitialize() + { + sCoInitStatus& cis = coInitStatus; + if( cis.code == S_OK ) + { + assert( cis.counter > 0 ); + cis.counter--; + if( 0 == cis.counter ) + CoUninitialize(); + } + } + + static CComAutoCriticalSection s_lock; +#define LOCK() CComCritSecLock<CComAutoCriticalSection> lock{ s_lock } + static uint32_t mfStartupCounter = 0; + + constexpr uint8_t FlagCOM = 1; + constexpr uint8_t FlagMF = 0x10; +} + +using namespace Whisper; + +MfStartupRaii::~MfStartupRaii() +{ + if( 0 != ( successFlags & FlagMF ) ) + { + LOCK(); + assert( mfStartupCounter > 0 ); + mfStartupCounter--; + if( mfStartupCounter > 0 ) + return; + MFShutdown(); + successFlags &= ~FlagMF; + } + + if( 0 != ( successFlags & FlagCOM ) ) + { + coUninitialize(); + successFlags &= ~FlagCOM; + } +} + +HRESULT MfStartupRaii::startup() +{ + if( 0 != ( successFlags & FlagMF ) ) + return HRESULT_FROM_WIN32( ERROR_ALREADY_INITIALIZED ); + + HRESULT hr = coInitialize(); + CHECK( hr ); + if( hr == S_OK ) + successFlags |= FlagCOM; + + LOCK(); + + if( 0 == mfStartupCounter ) + { + HRESULT hr = MFStartup( MF_VERSION, MFSTARTUP_LITE ); + if( SUCCEEDED( hr ) ) + { + mfStartupCounter = 1; + successFlags |= FlagMF; + return S_OK; + } + + if( 0 != ( successFlags & FlagCOM ) ) + { + coUninitialize(); + successFlags &= ~FlagCOM; + } + return hr; + } + else + { + mfStartupCounter++; + successFlags |= FlagMF; + return S_FALSE; + } +}
\ No newline at end of file |
