1#![allow(dead_code)]
6
7use std::cell::Cell;
8use std::ffi::c_void;
9use std::io;
10
11use windows::Win32::System::Com::{
12 CLSCTX_INPROC_SERVER,
13 COINIT_APARTMENTTHREADED,
14 CoCreateInstance,
15 CoInitializeEx,
16 CoTaskMemFree,
17};
18use windows::core::{
19 GUID,
20 Interface,
21};
22
23pub fn initialize_com() -> windows::core::Result<()> {
25 thread_local! {
26 static COM_INITIALIZED: Cell<bool> = const { Cell::new(false) };
27 }
28 COM_INITIALIZED.with(|initialized| {
29 if initialized.get() {
30 Ok(())
31 } else {
32 let init_result = unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED).ok() };
33 if let Ok(()) = init_result {
34 initialized.set(true);
35 }
36 init_result
37 }
38 })
39}
40
41pub(crate) trait ComInterfaceExt: Interface {
42 const CLASS_GUID: GUID;
43
44 fn new_instance() -> io::Result<Self> {
45 initialize_com()?;
46 let result = unsafe { CoCreateInstance(&Self::CLASS_GUID, None, CLSCTX_INPROC_SERVER) };
47 result.map_err(Into::into)
48 }
49}
50
51#[derive(Debug)]
53pub(crate) struct ComTaskMemory<T>(pub *mut T);
54
55impl<T> From<*mut T> for ComTaskMemory<T> {
56 fn from(value: *mut T) -> Self {
57 ComTaskMemory(value)
58 }
59}
60
61impl<T> Drop for ComTaskMemory<T> {
62 fn drop(&mut self) {
63 unsafe { CoTaskMemFree(Some(self.0.cast_const().cast::<c_void>())) }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn check_initialize_com() -> io::Result<()> {
73 initialize_com()?;
74 Ok(())
75 }
76}