| 1 | use super::*; |
| 2 | use core::ffi::c_void; |
| 3 | use 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)] |
| 12 | pub struct IUnknown(NonNull<c_void>); |
| 13 | |
| 14 | #[doc (hidden)] |
| 15 | #[repr (C)] |
| 16 | #[allow (non_camel_case_types)] |
| 17 | pub 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 | |
| 27 | unsafe impl Interface for IUnknown { |
| 28 | type Vtable = IUnknown_Vtbl; |
| 29 | const IID: GUID = GUID::from_u128(uuid:0x00000000_0000_0000_c000_000000000046); |
| 30 | } |
| 31 | |
| 32 | impl 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 | |
| 42 | impl Drop for IUnknown { |
| 43 | fn drop(&mut self) { |
| 44 | unsafe { |
| 45 | (self.vtable().Release)(core::mem::transmute_copy(self)); |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | impl 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 | |
| 66 | impl Eq for IUnknown {} |
| 67 | |
| 68 | impl 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)] |
| 79 | pub 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 | |
| 153 | impl 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 | |