1 use crate::*; 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)] 8 pub struct IUnknown(std::ptr::NonNull<std::ffi::c_void>); 9 10 #[repr(C)] 11 pub struct IUnknown_vtable( 12 pub unsafe extern "system" fn(this: RawPtr, iid: &Guid, interface: *mut RawPtr) -> HRESULT, 13 pub unsafe extern "system" fn(this: RawPtr) -> u32, 14 pub unsafe extern "system" fn(this: RawPtr) -> u32, 15 ); 16 17 unsafe impl Interface for IUnknown { 18 type Vtable = IUnknown_vtable; 19 20 const IID: Guid = Guid::from_values( 21 0x0000_0000, 22 0x0000, 23 0x0000, 24 [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46], 25 ); 26 } 27 28 impl Clone for IUnknown { clone(&self) -> Self29 fn clone(&self) -> Self { 30 unsafe { 31 (self.vtable().1)(self.abi()); // AddRef 32 } 33 34 Self(self.0) 35 } 36 } 37 38 impl Drop for IUnknown { drop(&mut self)39 fn drop(&mut self) { 40 unsafe { 41 (self.vtable().2)(self.abi()); // Release 42 } 43 } 44 } 45 46 impl PartialEq for IUnknown { eq(&self, other: &Self) -> bool47 fn eq(&self, other: &Self) -> bool { 48 // Since COM objects may implement multiple intefaces, COM identity can only 49 // be determined by querying for `IUnknown` explicitly and then comparing the 50 // pointer values. This works since `QueryInterface` is required to return 51 // the same pointer value for queries for `IUnknown`. 52 self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0 53 } 54 } 55 56 impl Eq for IUnknown {} 57 58 impl std::fmt::Debug for IUnknown { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 60 write!(f, "{:?}", self.0) 61 } 62 } 63