winapi_easy/
com.rs

1/*!
2Component Object Model (COM) initialization.
3*/
4
5#![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
23/// Initializes the COM library for the current thread. Will do nothing on further calls from the same thread.
24pub 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/// COM task memory location to be automatically freed.
52#[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}