use crate::sys::{
CoCreateInstance, CoGetClassObject, CoIncrementMTAUsage, CoInitializeEx, CoUninitialize,
CLSCTX_INPROC_SERVER, CLSID, COINIT_APARTMENTTHREADED, COINIT_MULTITHREADED, FAILED, HRESULT,
IID, S_FALSE, S_OK,
};
use core::ffi::c_void;
use crate::Interface;
pub fn init_runtime() -> Result<(), HRESULT> {
let mut _cookie = core::ptr::null_mut::<c_void>();
match unsafe { CoIncrementMTAUsage(&mut _cookie as *mut _ as *mut _) } {
S_OK => Ok(()),
hr => Err(hr),
}
}
#[repr(u32)]
#[non_exhaustive]
pub enum ApartmentType {
SingleThreaded = COINIT_APARTMENTTHREADED,
Multithreaded = COINIT_MULTITHREADED,
}
pub fn init_apartment(apartment_type: ApartmentType) -> Result<(), HRESULT> {
match unsafe { CoInitializeEx(core::ptr::null_mut::<c_void>(), apartment_type as u32) } {
S_OK | S_FALSE => Ok(()),
hr => Err(hr),
}
}
pub fn deinit_apartment() {
unsafe { CoUninitialize() }
}
pub struct ApartmentRuntime {
_priv: *const (), }
impl ApartmentRuntime {
pub fn new(apartment_type: ApartmentType) -> Result<Self, HRESULT> {
init_apartment(apartment_type)?;
Ok(Self {
_priv: core::ptr::null(),
})
}
}
impl Drop for ApartmentRuntime {
fn drop(&mut self) {
deinit_apartment()
}
}
pub fn get_class_object<T: Interface>(class_id: &CLSID) -> Result<T, HRESULT> {
let mut class = None;
let hr = unsafe {
CoGetClassObject(
class_id as *const CLSID,
CLSCTX_INPROC_SERVER,
core::ptr::null_mut::<c_void>(),
&T::IID as *const IID,
&mut class as *mut _ as _,
)
};
if FAILED(hr) {
return Err(hr);
}
Ok(class.unwrap())
}
pub fn create_instance<T: Interface>(class_id: &CLSID) -> Result<T, HRESULT> {
unsafe { create_raw_instance::<T>(class_id, core::ptr::null_mut()) }
}
unsafe fn create_raw_instance<T: Interface>(
class_id: &CLSID,
outer: *mut c_void,
) -> Result<T, HRESULT> {
let mut instance = None;
let hr = CoCreateInstance(
class_id as *const CLSID,
outer,
CLSCTX_INPROC_SERVER,
&T::IID as *const IID,
&mut instance as *mut _ as _,
);
if FAILED(hr) {
return Err(hr);
}
Ok(instance.unwrap())
}