1use super::*;
2
3/// All COM interfaces (and thus WinRT classes and interfaces) implement
4/// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown)
5/// under the hood to provide reference-counted lifetime management as well as the ability
6/// to query for additional interfaces that the object may implement.
7#[repr(transparent)]
8pub struct IUnknown(std::ptr::NonNull<std::ffi::c_void>);
9
10#[doc(hidden)]
11#[repr(C)]
12pub struct IUnknown_Vtbl {
13 pub QueryInterface: unsafe extern "system" fn(this: *mut std::ffi::c_void, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT,
14 pub AddRef: unsafe extern "system" fn(this: *mut std::ffi::c_void) -> u32,
15 pub Release: unsafe extern "system" fn(this: *mut std::ffi::c_void) -> u32,
16}
17
18unsafe impl Interface for IUnknown {
19 type Vtable = IUnknown_Vtbl;
20}
21
22unsafe impl ComInterface for IUnknown {
23 const IID: GUID = GUID::from_u128(uuid:0x00000000_0000_0000_c000_000000000046);
24}
25
26impl Clone for IUnknown {
27 fn clone(&self) -> Self {
28 unsafe {
29 (self.vtable().AddRef)(std::mem::transmute_copy(self));
30 }
31
32 Self(self.0)
33 }
34}
35
36impl Drop for IUnknown {
37 fn drop(&mut self) {
38 unsafe {
39 (self.vtable().Release)(std::mem::transmute_copy(self));
40 }
41 }
42}
43
44impl PartialEq for IUnknown {
45 fn eq(&self, other: &Self) -> bool {
46 // Since COM objects may implement multiple interfaces, COM identity can only
47 // be determined by querying for `IUnknown` explicitly and then comparing the
48 // pointer values. This works since `QueryInterface` is required to return
49 // the same pointer value for queries for `IUnknown`.
50 self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0
51 }
52}
53
54impl Eq for IUnknown {}
55
56impl std::fmt::Debug for IUnknown {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 f.debug_tuple(name:"IUnknown").field(&self.0).finish()
59 }
60}
61
62#[doc(hidden)]
63pub trait IUnknownImpl {
64 type Impl;
65 /// Get a reference to the backing implementation.
66 fn get_impl(&self) -> &Self::Impl;
67
68 /// The classic `QueryInterface` method from COM.
69 ///
70 /// # Safety
71 ///
72 /// This function is safe to call as long as the interface pointer is non-null and valid for writes
73 /// of an interface pointer.
74 unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT;
75 /// Increments the reference count of the interface
76 fn AddRef(&self) -> u32;
77 /// Decrements the reference count causing the interface's memory to be freed when the count is 0
78 ///
79 /// # Safety
80 ///
81 /// This function should only be called when the interfacer pointer is no longer used as calling `Release`
82 /// on a non-aliased interface pointer and then using that interface pointer may result in use after free.
83 unsafe fn Release(&self) -> u32;
84}
85
86#[cfg(feature = "implement")]
87impl IUnknown_Vtbl {
88 pub const fn new<T: IUnknownImpl, const OFFSET: isize>() -> Self {
89 unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT {
90 let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
91 (*this).QueryInterface(iid, interface)
92 }
93 unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void) -> u32 {
94 let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
95 (*this).AddRef()
96 }
97 unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void) -> u32 {
98 let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
99 (*this).Release()
100 }
101 Self { QueryInterface: QueryInterface::<T, OFFSET>, AddRef: AddRef::<T, OFFSET>, Release: Release::<T, OFFSET> }
102 }
103}
104