com_rs/macros.rs
1// Copyright (c) 2016 com-rs developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9/**
10Macro for generating COM interface definitions.
11
12# Usage
13```
14#[macro_use]
15extern crate com_rs;
16use com_rs::IUnknown;
17
18iid!(IID_IFOO =
19 0x12345678, 0x90AB, 0xCDEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
20
21com_interface! {
22 interface IFoo: IUnknown {
23 iid: IID_IFOO,
24 vtable: IFooVtbl,
25 fn foo() -> bool;
26 }
27}
28# fn main() { }
29```
30
31This example defines an interface called `IFoo`. In this case, the base type is
32IUnknown, the root COM type. The IID for the interface must also be defined,
33along with the name of the vtable type, `IFooVtbl`. This isn't publicly exposed,
34but there is currently no way to generate an ident within a macro so the callee
35must define one instead.
36
37The trait `Foo` defines the methods available for the interface, in this case
38a single method named `foo`. Note that any methods that return no value
39(e.g. the `void` type in C/C++) should return the unit type `()`.
40
41## Inheritance
42To define interfaces with a deeper hierarchy, add additional parent identifiers
43to the type definitions. e.g:
44
45```
46# #[macro_use]
47# extern crate com_rs;
48# use com_rs::IUnknown;
49# iid!(IID_IFOO = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
50# com_interface! {
51# interface IFoo: IUnknown {
52# iid: IID_IFOO,
53# vtable: IFooVtbl,
54# fn foo() -> bool;
55# }
56# }
57iid!(IID_IBAR =
58 0x12345678, 0x90AB, 0xCDEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
59com_interface! {
60 interface IBar: IFoo, IUnknown {
61 iid: IID_IBAR,
62 vtable: IBarVtbl,
63 fn bar(baz: i32) -> ();
64 }
65}
66# fn main() { }
67```
68
69This example defines an interface called `IBar` which extends `IFoo` from the
70previous example. Note that it is necessary to specify the parent types
71for both the interface and trait declarations.
72
73The interface hierarchy automates pointer conversion using the `AsComPtr` trait,
74and the trait hierarchy automatically implements the parent methods for the
75child interface.
76*/
77#[macro_export]
78macro_rules! com_interface {
79 (
80 $(#[$iface_attr:meta])*
81 interface $iface:ident: $base_iface:ty {
82 iid: $iid:ident,
83 vtable: $vtable:ident,
84 $(
85 $(#[$fn_attr:meta])*
86 fn $func:ident($($i:ident: $t:ty),*) -> $rt:ty;
87 )*
88 }
89 ) => (
90 #[allow(missing_debug_implementations)]
91 #[doc(hidden)]
92 #[repr(C)]
93 pub struct $vtable {
94 base: <$base_iface as $crate::ComInterface>::Vtable,
95 $($func: extern "stdcall" fn(*const $iface, $($t),*) -> $rt),*
96 }
97
98 $(#[$iface_attr])*
99 #[derive(Debug)]
100 #[repr(C)]
101 pub struct $iface {
102 vtable: *const $vtable
103 }
104
105 impl $iface {
106 $($(#[$fn_attr])*
107 pub unsafe fn $func(&self, $($i: $t),*) -> $rt {
108 ((*self.vtable).$func)(self $(,$i)*)
109 })*
110 }
111
112 impl ::std::ops::Deref for $iface {
113 type Target = $base_iface;
114 fn deref(&self) -> &$base_iface {
115 unsafe { ::std::mem::transmute(self) }
116 }
117 }
118
119 unsafe impl $crate::AsComPtr<$iface> for $iface {}
120 unsafe impl $crate::AsComPtr<$base_iface> for $iface {}
121
122 unsafe impl $crate::ComInterface for $iface {
123 #[doc(hidden)]
124 type Vtable = $vtable;
125 #[allow(unused_unsafe)]
126 fn iid() -> $crate::IID { unsafe { $iid } }
127 }
128 );
129
130 (
131 $(#[$iface_attr:meta])*
132 interface $iface:ident: $base_iface:ty, $($extra_base:ty),+ {
133 iid: $iid:ident,
134 vtable: $vtable:ident,
135 $(
136 $(#[$fn_attr:meta])*
137 fn $func:ident($($i:ident: $t:ty),*) -> $rt:ty;
138 )*
139 }
140 ) => (
141 com_interface! {
142 $(#[$iface_attr])*
143 interface $iface: $base_iface {
144 iid: $iid,
145 vtable: $vtable,
146 $($(#[$fn_attr])* fn $func($($i: $t),*) -> $rt;)*
147 }
148 }
149
150 $(unsafe impl $crate::AsComPtr<$extra_base> for $iface {})*
151 )
152}
153
154/**
155Helper macro for defining [`IID`](struct.IID.html) constants.
156
157# Usage
158```
159# #[macro_use]
160# extern crate com_rs;
161iid!(IID_IFOO = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
162# fn main() {}
163```
164
165IIDs are private by default as they are only supposed to be exposed by the
166`ComPtr::iid` method. If you want to make them public, just add the `pub`
167keyword before the identifier.
168
169```
170# #[macro_use]
171# extern crate com_rs;
172iid!(pub IID_IBAR = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
173# fn main() {}
174```
175
176*/
177#[macro_export]
178macro_rules! iid {
179 ($(#[$iid_attr:meta])*
180 $name:ident = $d1:expr, $d2:expr, $d3:expr, $($d4:expr),*) => (
181 $(#[$iid_attr])*
182 const $name: $crate::IID = $crate::IID {
183 data1: $d1,
184 data2: $d2,
185 data3: $d3,
186 data4: [$($d4),*],
187 };
188 );
189 ($(#[$iid_attr:meta])*
190 pub $name:ident = $d1:expr, $d2:expr, $d3:expr, $($d4:expr),*) => (
191 $(#[$iid_attr])*
192 pub const $name: $crate::IID = $crate::IID {
193 data1: $d1,
194 data2: $d2,
195 data3: $d3,
196 data4: [$($d4),*],
197 };
198 );
199}