1use super::*;
2use core::ffi::c_void;
3use core::ptr::NonNull;
4
5/// Base interface for all COM interfaces.
6///
7/// All COM interfaces (and thus WinRT classes and interfaces) implement
8/// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown)
9/// under the hood to provide reference-counted lifetime management as well as the ability
10/// to query for additional interfaces that the object may implement.
11#[repr(transparent)]
12pub struct IUnknown(NonNull<c_void>);
13
14#[doc(hidden)]
15#[repr(C)]
16#[allow(non_camel_case_types)]
17pub struct IUnknown_Vtbl {
18 pub QueryInterface: unsafe extern "system" fn(
19 this: *mut c_void,
20 iid: *const GUID,
21 interface: *mut *mut c_void,
22 ) -> HRESULT,
23 pub AddRef: unsafe extern "system" fn(this: *mut c_void) -> u32,
24 pub Release: unsafe extern "system" fn(this: *mut c_void) -> u32,
25}
26
27unsafe impl Interface for IUnknown {
28 type Vtable = IUnknown_Vtbl;
29 const IID: GUID = GUID::from_u128(uuid:0x00000000_0000_0000_c000_000000000046);
30}
31
32impl Clone for IUnknown {
33 fn clone(&self) -> Self {
34 unsafe {
35 (self.vtable().AddRef)(core::mem::transmute_copy(self));
36 }
37
38 Self(self.0)
39 }
40}
41
42impl Drop for IUnknown {
43 fn drop(&mut self) {
44 unsafe {
45 (self.vtable().Release)(core::mem::transmute_copy(self));
46 }
47 }
48}
49
50impl PartialEq for IUnknown {
51 fn eq(&self, other: &Self) -> bool {
52 // First we test for ordinary pointer equality. If two COM interface pointers have the
53 // same pointer value, then they are the same object. This can save us a lot of time,
54 // since calling QueryInterface is much more expensive than a single pointer comparison.
55 //
56 // However, interface pointers may have different values and yet point to the same object.
57 // Since COM objects may implement multiple interfaces, COM identity can only
58 // be determined by querying for `IUnknown` explicitly and then comparing the
59 // pointer values. This works since `QueryInterface` is required to return
60 // the same pointer value for queries for `IUnknown`.
61 self.as_raw() == other.as_raw()
62 || self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0
63 }
64}
65
66impl Eq for IUnknown {}
67
68impl core::fmt::Debug for IUnknown {
69 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70 f.debug_tuple(name:"IUnknown").field(&self.as_raw()).finish()
71 }
72}
73
74/// The `#[implement]` macro generates implementations of this trait for the types
75/// that it generates, e.g. `MyApp_Impl`,
76///
77/// `ComObject` uses this trait to interact with boxed COM objects.
78#[doc(hidden)]
79pub trait IUnknownImpl {
80 /// The contained user type, e.g. `MyApp`. Also known as the "inner" type.
81 type Impl;
82
83 /// Get a reference to the backing implementation.
84 fn get_impl(&self) -> &Self::Impl;
85
86 /// Get a mutable reference to the contained (inner) object.
87 fn get_impl_mut(&mut self) -> &mut Self::Impl;
88
89 /// Consumes the box and returns the contained (inner) object. This is the opposite of `new_box`.
90 fn into_inner(self) -> Self::Impl;
91
92 /// The classic `QueryInterface` method from COM.
93 ///
94 /// # Safety
95 ///
96 /// This function is safe to call as long as the interface pointer is non-null and valid for writes
97 /// of an interface pointer.
98 unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT;
99
100 /// Increments the reference count of the interface
101 fn AddRef(&self) -> u32;
102
103 /// Decrements the reference count causing the interface's memory to be freed when the count is 0
104 ///
105 /// # Safety
106 ///
107 /// This function should only be called when the interface pointer is no longer used as calling `Release`
108 /// on a non-aliased interface pointer and then using that interface pointer may result in use after free.
109 ///
110 /// This function takes `*mut Self` because the object may be freed by the time this method returns.
111 /// Taking `&self` would violate Rust's rules on reference lifetime.
112 unsafe fn Release(self_: *mut Self) -> u32;
113
114 /// Returns `true` if the reference count of the box is equal to 1.
115 fn is_reference_count_one(&self) -> bool;
116
117 /// Gets the trust level of the current object.
118 unsafe fn GetTrustLevel(&self, value: *mut i32) -> HRESULT;
119
120 /// Gets a borrowed reference to an interface that is implemented by this ComObject.
121 ///
122 /// The returned reference does not have an additional reference count.
123 /// You can AddRef it by calling to_owned().
124 #[inline(always)]
125 fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
126 where
127 Self: ComObjectInterface<I>,
128 {
129 <Self as ComObjectInterface<I>>::as_interface_ref(self)
130 }
131
132 /// Gets an owned (counted) reference to an interface that is implemented by this ComObject.
133 #[inline(always)]
134 fn to_interface<I: Interface>(&self) -> I
135 where
136 Self: ComObjectInterface<I>,
137 {
138 <Self as ComObjectInterface<I>>::as_interface_ref(self).to_owned()
139 }
140
141 /// Creates a new owned reference to this object.
142 ///
143 /// # Safety
144 ///
145 /// This function can only be safely called by `<Foo>_Impl` objects that are embedded in a
146 /// `ComObject`. Since we only allow safe Rust code to access these objects using a `ComObject`
147 /// or a `&<Foo>_Impl` that points within a `ComObject`, this is safe.
148 fn to_object(&self) -> ComObject<Self::Impl>
149 where
150 Self::Impl: ComObjectInner<Outer = Self>;
151}
152
153impl IUnknown_Vtbl {
154 pub const fn new<T: IUnknownImpl, const OFFSET: isize>() -> Self {
155 unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>(
156 this: *mut c_void,
157 iid: *const GUID,
158 interface: *mut *mut c_void,
159 ) -> HRESULT {
160 unsafe {
161 let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
162 (*this).QueryInterface(iid, interface)
163 }
164 }
165 unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>(
166 this: *mut c_void,
167 ) -> u32 {
168 unsafe {
169 let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
170 (*this).AddRef()
171 }
172 }
173 unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>(
174 this: *mut c_void,
175 ) -> u32 {
176 unsafe {
177 let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
178 T::Release(this)
179 }
180 }
181 Self {
182 QueryInterface: QueryInterface::<T, OFFSET>,
183 AddRef: AddRef::<T, OFFSET>,
184 Release: Release::<T, OFFSET>,
185 }
186 }
187}
188

Provided by KDAB

Privacy Policy