| Lift freeq's AV media plane out of sleek 90f8b89 nandi 19d ago | 1 | //! Handles COM initialization and cleanup. |
| 2 | |
| 3 | use std::io::Error as IoError; |
| 4 | use std::marker::PhantomData; |
| 5 | |
| 6 | use windows::Win32::Foundation::RPC_E_CHANGED_MODE; |
| 7 | use windows::Win32::System::Com::{CoInitializeEx, CoUninitialize, COINIT_APARTMENTTHREADED}; |
| 8 | |
| 9 | thread_local!(static COM_INITIALIZED: ComInitialized = { |
| 10 | unsafe { |
| 11 | // Try to initialize COM with STA by default to avoid compatibility issues with the ASIO |
| 12 | // backend (where CoInitialize() is called by the ASIO SDK) or winit (where drag and drop |
| 13 | // requires STA). |
| 14 | // This call can fail with RPC_E_CHANGED_MODE if another library initialized COM with MTA. |
| 15 | // That's OK though since COM ensures thread-safety/compatibility through marshalling when |
| 16 | // necessary. |
| 17 | let result = CoInitializeEx(None, COINIT_APARTMENTTHREADED); |
| 18 | if result.is_ok() || result == RPC_E_CHANGED_MODE { |
| 19 | ComInitialized { |
| 20 | result, |
| 21 | _ptr: PhantomData, |
| 22 | } |
| 23 | } else { |
| 24 | // COM initialization failed in another way, something is really wrong. |
| 25 | panic!( |
| 26 | "Failed to initialize COM: {}", |
| 27 | IoError::from_raw_os_error(result.0) |
| 28 | ); |
| 29 | } |
| 30 | } |
| 31 | }); |
| 32 | |
| 33 | /// RAII object that guards the fact that COM is initialized. |
| 34 | /// |
| 35 | // We store a raw pointer because it's the only way at the moment to remove `Send`/`Sync` from the |
| 36 | // object. |
| 37 | struct ComInitialized { |
| 38 | result: windows::core::HRESULT, |
| 39 | _ptr: PhantomData<*mut ()>, |
| 40 | } |
| 41 | |
| 42 | impl Drop for ComInitialized { |
| 43 | fn drop(&mut self) { |
| 44 | // Need to avoid calling CoUninitialize() if CoInitializeEx failed since it may have |
| 45 | // returned RPC_E_MODE_CHANGED - which is OK, see above. |
| 46 | if self.result.is_ok() { |
| 47 | unsafe { CoUninitialize() }; |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | /// Ensures that COM is initialized in this thread. |
| 53 | #[inline] |
| 54 | pub fn com_initialized() { |
| 55 | COM_INITIALIZED.with(|_| {}); |
| 56 | } |