use crate::sys::{
CoCreateInstance, CoGetClassObject, CoIncrementMTAUsage, CoInitializeEx, CoUninitialize,
CLSCTX_INPROC_SERVER, CLSID, COINIT_APARTMENTTHREADED, COINIT_MULTITHREADED, FAILED, HRESULT,
IID, S_FALSE, S_OK,
};
use std::ffi::c_void;
use crate::{CoClass, ComInterface, ComPtr, ComRc};
pub fn init_runtime() -> Result<(), HRESULT> {
let mut _cookie = std::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(std::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: std::ptr::null(),
})
}
}
impl Drop for ApartmentRuntime {
fn drop(&mut self) {
deinit_apartment()
}
}
pub fn get_class_object<T: ComInterface + ?Sized>(class_id: &CLSID) -> Result<ComRc<T>, HRESULT> {
let mut class = std::ptr::null_mut::<c_void>();
let hr = unsafe {
CoGetClassObject(
class_id as *const CLSID,
CLSCTX_INPROC_SERVER,
std::ptr::null_mut::<c_void>(),
&T::IID as *const IID,
&mut class as *mut *mut c_void,
)
};
if FAILED(hr) {
return Err(hr);
}
Ok(unsafe { ComRc::from_raw(class as *mut *mut _) })
}
pub fn create_instance<T: ComInterface + ?Sized>(class_id: &CLSID) -> Result<ComRc<T>, HRESULT> {
unsafe {
Ok(ComRc::new(create_raw_instance::<T>(
class_id,
std::ptr::null_mut(),
)?))
}
}
pub fn create_aggregated_instance<T: ComInterface + ?Sized, U: CoClass>(
class_id: &CLSID,
outer: &mut U,
) -> Result<ComPtr<T>, HRESULT> {
unsafe { create_raw_instance::<T>(class_id, outer as *mut U as *mut c_void) }
}
unsafe fn create_raw_instance<T: ComInterface + ?Sized>(
class_id: &CLSID,
outer: *mut c_void,
) -> Result<ComPtr<T>, HRESULT> {
let mut instance = std::ptr::null_mut::<c_void>();
let hr = CoCreateInstance(
class_id as *const CLSID,
outer,
CLSCTX_INPROC_SERVER,
&T::IID as *const IID,
&mut instance as *mut *mut c_void,
);
if FAILED(hr) {
return Err(hr);
}
Ok(ComPtr::new(instance as *mut _))
}