winapi_easy/
com.rs

1/*!
2Component Object Model (COM) initialization.
3*/
4
5#![allow(dead_code)]
6
7use std::cell::Cell;
8use std::io;
9
10use windows::core::{
11    Interface,
12    GUID,
13};
14use windows::Win32::System::Com::{
15    CoCreateInstance,
16    CoInitializeEx,
17    CoTaskMemFree,
18    CLSCTX_INPROC_SERVER,
19    COINIT_APARTMENTTHREADED,
20};
21
22/// Initializes the COM library for the current thread. Will do nothing on further calls from the same thread.
23pub fn initialize_com() -> windows::core::Result<()> {
24    thread_local! {
25        static COM_INITIALIZED: Cell<bool> = const { Cell::new(false) };
26    }
27    COM_INITIALIZED.with(|initialized| {
28        if !initialized.get() {
29            let init_result = unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED).ok() };
30            if let Ok(()) = init_result {
31                initialized.set(true);
32            }
33            init_result
34        } else {
35            Ok(())
36        }
37    })
38}
39
40pub(crate) trait ComInterfaceExt: Interface {
41    const CLASS_GUID: GUID;
42
43    fn new_instance() -> io::Result<Self> {
44        initialize_com()?;
45        let result = unsafe { CoCreateInstance(&Self::CLASS_GUID, None, CLSCTX_INPROC_SERVER) };
46        result.map_err(Into::into)
47    }
48}
49
50/// COM task memory location to be automatically freed.
51#[derive(Debug)]
52pub(crate) struct ComTaskMemory<T>(pub *mut T);
53
54impl<T> From<*mut T> for ComTaskMemory<T> {
55    fn from(value: *mut T) -> Self {
56        ComTaskMemory(value)
57    }
58}
59
60impl<T> Drop for ComTaskMemory<T> {
61    fn drop(&mut self) {
62        unsafe { CoTaskMemFree(Some(self.0 as *mut _)) }
63    }
64}