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
|
// This is only handy for implementing a single-interface-implementing IUnknown.
macro_rules! implement_iunknown {
($interface:ident, $typ:ident) => {
IUnknownVtbl {
QueryInterface: {
#[allow(non_snake_case)]
unsafe extern "system" fn QueryInterface(
unknown_this: *mut IUnknown,
riid: REFIID,
ppv_object: *mut *mut c_void,
) -> HRESULT {
use $crate::winapi::Interface;
let this = if $crate::winapi::shared::guiddef::IsEqualGUID(
&*riid,
&$interface::uuidof(),
) {
mem::transmute(unknown_this)
} else if $crate::winapi::shared::guiddef::IsEqualGUID(
&*riid,
&IUnknown::uuidof(),
) {
mem::transmute(unknown_this)
} else {
return $crate::winapi::shared::winerror::E_NOINTERFACE;
};
(*unknown_this).AddRef();
*ppv_object = this;
return S_OK;
}
QueryInterface
},
AddRef: {
unsafe extern "system" fn AddRef(unknown_this: *mut IUnknown) -> ULONG {
let this = $typ::from_interface(unknown_this);
let count = this.refcount.fetch_add(1, atomic::Ordering::Relaxed) + 1;
count as ULONG
}
AddRef
},
Release: {
unsafe extern "system" fn Release(unknown_this: *mut IUnknown) -> ULONG {
let this = $typ::from_interface(unknown_this);
let count = this.refcount.fetch_sub(1, atomic::Ordering::Release) - 1;
if count == 0 {
<$typ as Com<$interface>>::destroy(unknown_this as *mut $interface);
}
count as ULONG
}
Release
},
}
};
(static $interface:ident, $typ:ident) => {
IUnknownVtbl {
QueryInterface: {
#[allow(non_snake_case)]
unsafe extern "system" fn QueryInterface(
unknown_this: *mut IUnknown,
riid: REFIID,
ppvObject: *mut *mut $crate::winapi::ctypes::c_void,
) -> HRESULT {
use $crate::winapi::Interface;
let this = if $crate::winapi::shared::guiddef::IsEqualGUID(
&*riid,
&$interface::uuidof(),
) {
mem::transmute(unknown_this)
} else if $crate::winapi::shared::guiddef::IsEqualGUID(
&*riid,
&IUnknown::uuidof(),
) {
mem::transmute(unknown_this)
} else {
return $crate::winapi::shared::winerror::E_NOINTERFACE;
};
(*unknown_this).AddRef();
*ppvObject = this;
return S_OK;
}
QueryInterface
},
AddRef: {
// FIXME(pcwalton): Uh? Maybe we should actually reference count?
#[allow(non_snake_case)]
unsafe extern "system" fn AddRef(_: *mut IUnknown) -> ULONG {
1
}
AddRef
},
Release: {
#[allow(non_snake_case)]
unsafe extern "system" fn Release(_: *mut IUnknown) -> ULONG {
1
}
Release
},
}
};
}
#[repr(C)]
pub struct ComRepr<Type, Vtbl>(*const Vtbl, Type);
pub trait Com<Interface>
where
Self: Sized,
{
type Vtbl: 'static;
fn vtbl() -> &'static Self::Vtbl;
fn into_interface(self) -> *mut Interface {
let com = Box::new(ComRepr(Self::vtbl(), self));
Box::into_raw(com) as *mut Interface
}
unsafe fn from_interface<'a>(thing: *mut Interface) -> &'a mut Self {
&mut (*(thing as *mut ComRepr<Self, Self::Vtbl>)).1
}
unsafe fn destroy(thing: *mut Interface) {
Box::from_raw(thing as *mut ComRepr<Self, Self::Vtbl>);
}
}
|