1use super::*;
2use core::any::Any;
3use core::ffi::c_void;
4use core::marker::PhantomData;
5use core::mem::{forget, transmute_copy, MaybeUninit};
6use core::ptr::NonNull;
7
8/// Provides low-level access to an interface vtable.
9///
10/// This trait is automatically implemented by the generated bindings and should not be
11/// implemented manually.
12///
13/// # Safety
14pub unsafe trait Interface: Sized + Clone {
15 #[doc(hidden)]
16 type Vtable;
17
18 /// The `GUID` associated with the interface.
19 const IID: GUID;
20
21 #[doc(hidden)]
22 const UNKNOWN: bool = true;
23
24 /// A reference to the interface's vtable
25 #[doc(hidden)]
26 #[inline(always)]
27 fn vtable(&self) -> &Self::Vtable {
28 // SAFETY: the implementor of the trait guarantees that `Self` is castable to its vtable
29 unsafe { self.assume_vtable::<Self>() }
30 }
31
32 /// Cast this interface as a reference to the supplied interfaces `Vtable`
33 ///
34 /// # Safety
35 ///
36 /// This is safe if `T` is an equivalent interface to `Self` or a super interface.
37 /// In other words, `T::Vtable` must be equivalent to the beginning of `Self::Vtable`.
38 #[doc(hidden)]
39 #[inline(always)]
40 unsafe fn assume_vtable<T: Interface>(&self) -> &T::Vtable {
41 unsafe { &**(self.as_raw() as *mut *mut T::Vtable) }
42 }
43
44 /// Returns the raw COM interface pointer. The resulting pointer continues to be owned by the `Interface` implementation.
45 #[inline(always)]
46 fn as_raw(&self) -> *mut c_void {
47 // SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation
48 unsafe { transmute_copy(self) }
49 }
50
51 /// Returns the raw COM interface pointer and releases ownership. It the caller's responsibility to release the COM interface pointer.
52 #[inline(always)]
53 fn into_raw(self) -> *mut c_void {
54 // SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation
55 let raw = self.as_raw();
56 forget(self);
57 raw
58 }
59
60 /// Creates an `Interface` by taking ownership of the `raw` COM interface pointer.
61 ///
62 /// # Safety
63 ///
64 /// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words,
65 /// it must point to a vtable beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
66 unsafe fn from_raw(raw: *mut c_void) -> Self {
67 unsafe { transmute_copy(&raw) }
68 }
69
70 /// Creates an `Interface` that is valid so long as the `raw` COM interface pointer is valid.
71 ///
72 /// # Safety
73 ///
74 /// The `raw` pointer must be a valid COM interface pointer. In other words, it must point to a vtable
75 /// beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
76 #[inline(always)]
77 unsafe fn from_raw_borrowed(raw: &*mut c_void) -> Option<&Self> {
78 unsafe {
79 if raw.is_null() {
80 None
81 } else {
82 Some(transmute_copy(&raw))
83 }
84 }
85 }
86
87 /// Attempts to cast the current interface to another interface using `QueryInterface`.
88 ///
89 /// The name `cast` is preferred to `query` because there is a WinRT method named query but not one
90 /// named cast.
91 #[inline(always)]
92 fn cast<T: Interface>(&self) -> Result<T> {
93 // SAFETY: `result` is valid for writing an interface pointer and it is safe
94 // to cast the `result` pointer as `T` on success because we are using the `IID` tied
95 // to `T` which the implementor of `Interface` has guaranteed is correct
96 unsafe {
97 // If query() returns a failure code then we propagate that failure code to the caller.
98 // In that case, we ignore the contents of 'result' (which will _not_ be dropped,
99 // because MaybeUninit intentionally does not drop its contents).
100 //
101 // This guards against implementations of COM interfaces which may store non-null values
102 // in 'result' but still return E_NOINTERFACE.
103 let mut result = MaybeUninit::<Option<T>>::zeroed();
104 self.query(&T::IID, result.as_mut_ptr() as _).ok()?;
105
106 // If we get here, then query() has succeeded, but we still need to double-check
107 // that the output pointer is non-null.
108 if let Some(obj) = result.assume_init() {
109 Ok(obj)
110 } else {
111 Err(imp::E_POINTER.into())
112 }
113 }
114 }
115
116 /// This casts the given COM interface to [`&dyn Any`].
117 ///
118 /// Applications should generally _not_ call this method directly. Instead, use the
119 /// [`Interface::cast_object_ref`] or [`Interface::cast_object`] methods.
120 ///
121 /// `T` must be a type that has been annotated with `#[implement]`; this is checked at
122 /// compile-time by the generic constraints of this method. However, note that the
123 /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
124 /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
125 ///
126 /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
127 /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
128 ///
129 /// # Safety
130 ///
131 /// **IMPORTANT!!** This uses a non-standard protocol for QueryInterface! The `DYNAMIC_CAST_IID`
132 /// IID identifies this protocol, but there is no `IDynamicCast` interface. Instead, objects
133 /// that recognize `DYNAMIC_CAST_IID` simply store their `&dyn Any` directly at the interface
134 /// pointer that was passed to `QueryInterface. This means that the returned value has a
135 /// size that is twice as large (`size_of::<&dyn Any>() == 2 * size_of::<*const c_void>()`).
136 ///
137 /// This means that callers that use this protocol cannot simply pass `&mut ptr` for
138 /// an ordinary single-pointer-sized pointer. Only this method understands this protocol.
139 ///
140 /// Another part of this protocol is that the implementation of `QueryInterface` _does not_
141 /// AddRef the object. The caller must guarantee the liveness of the COM object. In Rust,
142 /// this means tying the lifetime of the IUnknown* that we used for the QueryInterface
143 /// call to the lifetime of the returned `&dyn Any` value.
144 ///
145 /// This method preserves type safety and relies on these invariants:
146 ///
147 /// * All `QueryInterface` implementations that recognize `DYNAMIC_CAST_IID` are generated by
148 /// the `#[implement]` macro and respect the rules described here.
149 #[inline(always)]
150 fn cast_to_any<T>(&self) -> Result<&dyn Any>
151 where
152 T: ComObjectInner,
153 T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
154 {
155 unsafe {
156 let mut any_ref_arg: MaybeUninit<&dyn Any> = MaybeUninit::zeroed();
157 self.query(
158 &DYNAMIC_CAST_IID,
159 any_ref_arg.as_mut_ptr() as *mut *mut c_void,
160 )
161 .ok()?;
162 Ok(any_ref_arg.assume_init())
163 }
164 }
165
166 /// Returns `true` if the given COM interface refers to an implementation of `T`.
167 ///
168 /// `T` must be a type that has been annotated with `#[implement]`; this is checked at
169 /// compile-time by the generic constraints of this method.
170 ///
171 /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
172 /// object that contains non-static lifetimes, then this function will return `false`.
173 #[inline(always)]
174 fn is_object<T>(&self) -> bool
175 where
176 T: ComObjectInner,
177 T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
178 {
179 if let Ok(any) = self.cast_to_any::<T>() {
180 any.is::<T::Outer>()
181 } else {
182 false
183 }
184 }
185
186 /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
187 /// object, e.g. `&MyApp_Impl`, not the inner `&MyApp` object.
188 ///
189 /// `T` must be a type that has been annotated with `#[implement]`; this is checked at
190 /// compile-time by the generic constraints of this method. However, note that the
191 /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
192 /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
193 ///
194 /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
195 /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
196 ///
197 /// The returned value is borrowed. If you need an owned (counted) reference, then use
198 /// [`Interface::cast_object`].
199 #[inline(always)]
200 fn cast_object_ref<T>(&self) -> Result<&T::Outer>
201 where
202 T: ComObjectInner,
203 T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
204 {
205 let any: &dyn Any = self.cast_to_any::<T>()?;
206 if let Some(outer) = any.downcast_ref::<T::Outer>() {
207 Ok(outer)
208 } else {
209 Err(imp::E_NOINTERFACE.into())
210 }
211 }
212
213 /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
214 /// object, e.g. `MyApp_Impl`, not the inner `MyApp` object.
215 ///
216 /// `T` must be a type that has been annotated with `#[implement]`; this is checked at
217 /// compile-time by the generic constraints of this method. However, note that the
218 /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
219 /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
220 ///
221 /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
222 /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
223 ///
224 /// The returned value is an owned (counted) reference; this function calls `AddRef` on the
225 /// underlying COM object. If you do not need an owned reference, then you can use the
226 /// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`.
227 #[inline(always)]
228 fn cast_object<T>(&self) -> Result<ComObject<T>>
229 where
230 T: ComObjectInner,
231 T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
232 {
233 let object_ref = self.cast_object_ref::<T>()?;
234 Ok(object_ref.to_object())
235 }
236
237 /// Attempts to create a [`Weak`] reference to this object.
238 fn downgrade(&self) -> Result<Weak<Self>> {
239 self.cast::<imp::IWeakReferenceSource>()
240 .and_then(|source| Weak::downgrade(&source))
241 }
242
243 /// Call `QueryInterface` on this interface
244 ///
245 /// # Safety
246 ///
247 /// `interface` must be a non-null, valid pointer for writing an interface pointer.
248 #[inline(always)]
249 unsafe fn query(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT {
250 unsafe {
251 if Self::UNKNOWN {
252 (self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface)
253 } else {
254 panic!("Non-COM interfaces cannot be queried.")
255 }
256 }
257 }
258
259 /// Creates an `InterfaceRef` for this reference. The `InterfaceRef` tracks lifetimes statically,
260 /// and eliminates the need for dynamic reference count adjustments (AddRef/Release).
261 fn to_ref(&self) -> InterfaceRef<'_, Self> {
262 InterfaceRef::from_interface(self)
263 }
264}
265
266/// This has the same memory representation as `IFoo`, but represents a borrowed interface pointer.
267///
268/// This type has no `Drop` impl; it does not AddRef/Release the given interface. However, because
269/// it has a lifetime parameter, it always represents a non-null pointer to an interface.
270#[repr(transparent)]
271pub struct InterfaceRef<'a, I>(NonNull<c_void>, PhantomData<&'a I>);
272
273impl<I> Copy for InterfaceRef<'_, I> {}
274
275impl<I> Clone for InterfaceRef<'_, I> {
276 fn clone(&self) -> Self {
277 *self
278 }
279}
280
281impl<I: core::fmt::Debug + Interface> core::fmt::Debug for InterfaceRef<'_, I> {
282 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
283 <I as core::fmt::Debug>::fmt(&**self, f)
284 }
285}
286
287impl<I: Interface> InterfaceRef<'_, I> {
288 /// Creates an `InterfaceRef` from a raw pointer. _This is extremely dangerous, since there
289 /// is no lifetime tracking at all!_
290 ///
291 /// # Safety
292 /// The caller must guarantee that the `'a` lifetime parameter is bound by context to a correct
293 /// lifetime.
294 #[inline(always)]
295 pub unsafe fn from_raw(ptr: NonNull<c_void>) -> Self {
296 Self(ptr, PhantomData)
297 }
298
299 /// Creates an `InterfaceRef` from an interface reference. This safely associates the lifetime
300 /// of the interface reference with the `'a` parameter of `InterfaceRef`. This allows for
301 /// lifetime checking _without_ calling AddRef/Release on the underlying lifetime, which can
302 /// improve efficiency.
303 #[inline(always)]
304 pub fn from_interface(interface: &I) -> Self {
305 unsafe {
306 // SAFETY: new_unchecked() should be valid because Interface::as_raw should always
307 // return a non-null pointer.
308 Self(NonNull::new_unchecked(interface.as_raw()), PhantomData)
309 }
310 }
311
312 /// Calls AddRef on the underlying COM interface and returns an "owned" (counted) reference.
313 #[inline(always)]
314 pub fn to_owned(self) -> I {
315 (*self).clone()
316 }
317}
318
319impl<'a, 'i: 'a, I: Interface> From<&'i I> for InterfaceRef<'a, I> {
320 #[inline(always)]
321 fn from(interface: &'a I) -> InterfaceRef<'a, I> {
322 InterfaceRef::from_interface(interface)
323 }
324}
325
326impl<I: Interface> core::ops::Deref for InterfaceRef<'_, I> {
327 type Target = I;
328
329 #[inline(always)]
330 fn deref(&self) -> &I {
331 unsafe { core::mem::transmute(self) }
332 }
333}
334
335/// This IID identifies a special protocol, used by [`Interface::cast_to_any`]. This is _not_
336/// an ordinary COM interface; it uses special lifetime rules and a larger interface pointer.
337/// See the comments on [`Interface::cast_to_any`].
338#[doc(hidden)]
339pub const DYNAMIC_CAST_IID: GUID = GUID::from_u128(uuid:0xae49d5cb_143f_431c_874c_2729336e4eca);
340