1 // This is only handy for implementing a single-interface-implementing IUnknown. 2 3 macro_rules! implement_iunknown { 4 ($interface:ident, $typ:ident) => { 5 IUnknownVtbl { 6 QueryInterface: { 7 #[allow(non_snake_case)] 8 unsafe extern "system" fn QueryInterface( 9 unknown_this: *mut IUnknown, 10 riid: REFIID, 11 ppv_object: *mut *mut c_void, 12 ) -> HRESULT { 13 use $crate::winapi::Interface; 14 let this = if $crate::winapi::shared::guiddef::IsEqualGUID( 15 &*riid, 16 &$interface::uuidof(), 17 ) { 18 mem::transmute(unknown_this) 19 } else if $crate::winapi::shared::guiddef::IsEqualGUID( 20 &*riid, 21 &IUnknown::uuidof(), 22 ) { 23 mem::transmute(unknown_this) 24 } else { 25 return $crate::winapi::shared::winerror::E_NOINTERFACE; 26 }; 27 28 (*unknown_this).AddRef(); 29 *ppv_object = this; 30 return S_OK; 31 } 32 QueryInterface 33 }, 34 AddRef: { 35 unsafe extern "system" fn AddRef(unknown_this: *mut IUnknown) -> ULONG { 36 let this = $typ::from_interface(unknown_this); 37 let count = this.refcount.fetch_add(1, atomic::Ordering::Relaxed) + 1; 38 count as ULONG 39 } 40 AddRef 41 }, 42 Release: { 43 unsafe extern "system" fn Release(unknown_this: *mut IUnknown) -> ULONG { 44 let this = $typ::from_interface(unknown_this); 45 let count = this.refcount.fetch_sub(1, atomic::Ordering::Release) - 1; 46 if count == 0 { 47 <$typ as Com<$interface>>::destroy(unknown_this as *mut $interface); 48 } 49 count as ULONG 50 } 51 Release 52 }, 53 } 54 }; 55 (static $interface:ident, $typ:ident) => { 56 IUnknownVtbl { 57 QueryInterface: { 58 #[allow(non_snake_case)] 59 unsafe extern "system" fn QueryInterface( 60 unknown_this: *mut IUnknown, 61 riid: REFIID, 62 ppvObject: *mut *mut $crate::winapi::ctypes::c_void, 63 ) -> HRESULT { 64 use $crate::winapi::Interface; 65 let this = if $crate::winapi::shared::guiddef::IsEqualGUID( 66 &*riid, 67 &$interface::uuidof(), 68 ) { 69 mem::transmute(unknown_this) 70 } else if $crate::winapi::shared::guiddef::IsEqualGUID( 71 &*riid, 72 &IUnknown::uuidof(), 73 ) { 74 mem::transmute(unknown_this) 75 } else { 76 return $crate::winapi::shared::winerror::E_NOINTERFACE; 77 }; 78 79 (*unknown_this).AddRef(); 80 *ppvObject = this; 81 return S_OK; 82 } 83 QueryInterface 84 }, 85 AddRef: { 86 // FIXME(pcwalton): Uh? Maybe we should actually reference count? 87 #[allow(non_snake_case)] 88 unsafe extern "system" fn AddRef(_: *mut IUnknown) -> ULONG { 89 1 90 } 91 AddRef 92 }, 93 Release: { 94 #[allow(non_snake_case)] 95 unsafe extern "system" fn Release(_: *mut IUnknown) -> ULONG { 96 1 97 } 98 Release 99 }, 100 } 101 }; 102 } 103 104 #[repr(C)] 105 pub struct ComRepr<Type, Vtbl>(*const Vtbl, Type); 106 107 pub trait Com<Interface> 108 where 109 Self: Sized, 110 { 111 type Vtbl: 'static; 112 vtbl() -> &'static Self::Vtbl113 fn vtbl() -> &'static Self::Vtbl; 114 into_interface(self) -> *mut Interface115 fn into_interface(self) -> *mut Interface { 116 let com = Box::new(ComRepr(Self::vtbl(), self)); 117 Box::into_raw(com) as *mut Interface 118 } 119 from_interface<'a>(thing: *mut Interface) -> &'a mut Self120 unsafe fn from_interface<'a>(thing: *mut Interface) -> &'a mut Self { 121 &mut (*(thing as *mut ComRepr<Self, Self::Vtbl>)).1 122 } 123 destroy(thing: *mut Interface)124 unsafe fn destroy(thing: *mut Interface) { 125 Box::from_raw(thing as *mut ComRepr<Self, Self::Vtbl>); 126 } 127 } 128