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