1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use super::*;
use core::ffi::c_void;
use core::ptr::NonNull;
/// Base interface for all COM interfaces.
///
/// All COM interfaces (and thus WinRT classes and interfaces) implement
/// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown)
/// to provide reference-counted lifetime management as well as the ability
/// to query for additional interfaces that the object may implement.
#[repr(transparent)]
pub struct IUnknown(NonNull<c_void>);
#[doc(hidden)]
#[repr(C)]
pub struct IUnknown_Vtbl {
pub QueryInterface: unsafe extern "system" fn(
this: *mut c_void,
iid: *const GUID,
interface: *mut *mut c_void,
) -> HRESULT,
pub AddRef: unsafe extern "system" fn(this: *mut c_void) -> u32,
pub Release: unsafe extern "system" fn(this: *mut c_void) -> u32,
}
unsafe impl Interface for IUnknown {
type Vtable = IUnknown_Vtbl;
const IID: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
}
impl Clone for IUnknown {
fn clone(&self) -> Self {
unsafe {
(self.vtable().AddRef)(self.as_raw());
}
Self(self.0)
}
}
impl Drop for IUnknown {
fn drop(&mut self) {
unsafe {
(self.vtable().Release)(self.as_raw());
}
}
}
impl PartialEq for IUnknown {
fn eq(&self, other: &Self) -> bool {
// COM identity requires comparing canonical IUnknown pointers unless these pointers match.
core::ptr::eq(self.as_raw(), other.as_raw())
|| self.cast::<Self>().unwrap().0 == other.cast::<Self>().unwrap().0
}
}
impl Eq for IUnknown {}
impl core::fmt::Debug for IUnknown {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_tuple("IUnknown").field(&self.as_raw()).finish()
}
}
/// Internal access to the outer type generated by `#[implement]`.
#[doc(hidden)]
pub trait IUnknownImpl {
/// The contained user type, such as `MyApp`.
type Impl;
/// Returns the contained object.
fn get_impl(&self) -> &Self::Impl;
/// Returns the contained object mutably.
fn get_impl_mut(&mut self) -> &mut Self::Impl;
/// Consumes the outer object and returns the contained object.
fn into_inner(self) -> Self::Impl;
/// Implements COM `QueryInterface`.
///
/// # Safety
///
/// `iid` must be readable and `interface` must accept one writable pointer.
unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT;
/// Increments the reference count.
fn AddRef(&self) -> u32;
/// Decrements the reference count.
///
/// # Safety
///
/// The interface pointer must not be used after this call because the object may be freed.
///
/// The raw receiver avoids extending a reference beyond the possible destruction.
unsafe fn Release(self_: *mut Self) -> u32;
/// Returns `true` if the reference count of the box is equal to 1.
fn is_reference_count_one(&self) -> bool;
/// Gets the trust level of the current object.
unsafe fn GetTrustLevel(&self, value: *mut i32) -> HRESULT;
/// Gets a borrowed reference to an interface that is implemented by this ComObject.
///
/// The returned reference does not have an additional reference count.
/// You can AddRef it by calling to_owned().
#[inline(always)]
fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
where
Self: ComObjectInterface<I>,
{
<Self as ComObjectInterface<I>>::as_interface_ref(self)
}
/// Gets an owned (counted) reference to an interface that is implemented by this ComObject.
#[inline(always)]
fn to_interface<I: Interface>(&self) -> I
where
Self: ComObjectInterface<I>,
{
<Self as ComObjectInterface<I>>::as_interface_ref(self).to_owned()
}
/// Creates a new owned reference to this object.
///
/// # Safety
///
/// This function can only be safely called by `<Foo>_Impl` objects that are embedded in a
/// `ComObject`. Since we only allow safe Rust code to access these objects using a `ComObject`
/// or a `&<Foo>_Impl` that points within a `ComObject`, this is safe.
fn to_object(&self) -> ComObject<Self::Impl>
where
Self::Impl: ComObjectInner<Outer = Self>;
}
impl IUnknown_Vtbl {
pub const fn new<T: IUnknownImpl, const OFFSET: isize>() -> Self {
unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>(
this: *mut c_void,
iid: *const GUID,
interface: *mut *mut c_void,
) -> HRESULT {
unsafe {
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
(*this).QueryInterface(iid, interface)
}
}
unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>(
this: *mut c_void,
) -> u32 {
unsafe {
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
(*this).AddRef()
}
}
unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>(
this: *mut c_void,
) -> u32 {
unsafe {
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
T::Release(this)
}
}
Self {
QueryInterface: QueryInterface::<T, OFFSET>,
AddRef: AddRef::<T, OFFSET>,
Release: Release::<T, OFFSET>,
}
}
}