Skip to main content

ferroui_microcom/
unknown.rs

1use std::ffi::c_void;
2
3use crate::{Guid, RawHResult};
4
5/// Implemented (by generated code) for every COM interface type.
6///
7/// # Safety
8/// `Self` must be `#[repr(C)]` with a single field: a pointer to
9/// `Self::Vtbl`, and `Self::Vtbl` must start with the vtable of the base
10/// interface (ultimately [`IUnknownVtbl`]).
11pub unsafe trait Interface: Sized + 'static {
12    /// The interface's IID as written in the IDL.
13    const IID: Guid;
14    /// IDL name, for diagnostics.
15    const NAME: &'static str;
16    type Vtbl: 'static;
17
18    /// `true` if `iid` names this interface or one of its bases (including
19    /// `IUnknown`). Both the IDL value and the value materialized by `com.h`
20    /// (see [`Guid::as_com_h_materialized`]) are accepted.
21    fn matches_iid(iid: &Guid) -> bool;
22
23    #[inline]
24    fn as_unknown(&self) -> &IUnknown {
25        // SAFETY: guaranteed by the trait contract.
26        unsafe { &*(self as *const Self as *const IUnknown) }
27    }
28
29    #[inline]
30    fn as_raw(&self) -> *mut Self {
31        self as *const Self as *mut Self
32    }
33}
34
35#[repr(C)]
36pub struct IUnknownVtbl {
37    pub query_interface: unsafe extern "system" fn(
38        this: *mut c_void,
39        riid: *const Guid,
40        ppv: *mut *mut c_void,
41    ) -> RawHResult,
42    pub add_ref: unsafe extern "system" fn(this: *mut c_void) -> u32,
43    pub release: unsafe extern "system" fn(this: *mut c_void) -> u32,
44}
45
46/// The root interface. A `*mut IUnknown` is a native `IUnknown*`.
47#[repr(C)]
48pub struct IUnknown {
49    vtbl: *const IUnknownVtbl,
50}
51
52unsafe impl Interface for IUnknown {
53    const IID: Guid = Guid::from_u128(0x00000000_0000_0000_C000_000000000046);
54    const NAME: &'static str = "IUnknown";
55    type Vtbl = IUnknownVtbl;
56
57    fn matches_iid(iid: &Guid) -> bool {
58        *iid == Self::IID || *iid == Self::IID.as_com_h_materialized()
59    }
60}
61
62impl IUnknown {
63    /// # Safety
64    /// Raw COM call; `ppv` must be valid for writes.
65    #[inline]
66    pub unsafe fn query_interface_raw(&self, riid: &Guid, ppv: *mut *mut c_void) -> RawHResult {
67        ((*self.vtbl).query_interface)(self as *const _ as *mut c_void, riid, ppv)
68    }
69
70    /// # Safety
71    /// Raw reference-count manipulation.
72    #[inline]
73    pub unsafe fn add_ref(&self) -> u32 {
74        ((*self.vtbl).add_ref)(self as *const _ as *mut c_void)
75    }
76
77    /// # Safety
78    /// Raw reference-count manipulation; `self` may be dangling afterwards.
79    #[inline]
80    pub unsafe fn release(&self) -> u32 {
81        ((*self.vtbl).release)(self as *const _ as *mut c_void)
82    }
83}
84
85/// Implementation-side counterpart of [`IUnknown`]: the root of every
86/// generated `I...Impl` trait hierarchy. It has no methods — reference
87/// counting and `QueryInterface` are provided by [`crate::ComObject`] — and
88/// is blanket-implemented for every type.
89pub trait IUnknownImpl {}
90impl<T: ?Sized> IUnknownImpl for T {}