1#![warn(missing_docs)]
2#![warn(clippy::pedantic)]
3#![doc = include_str!("../README.md")]
4
5use std::mem::ManuallyDrop;
6
7use windows::{
8 Win32::{
9 Foundation::VARIANT_BOOL,
10 System::{
11 Com::{DISPATCH_METHOD, DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT, DISPPARAMS},
12 Variant::{
13 VAR_CHANGE_FLAGS, VARIANT_0_0, VT_BOOL, VT_BSTR, VT_DISPATCH, VT_I2, VT_I4, VT_I8,
14 VT_NULL, VT_UI1, VT_UI2, VT_UI4, VT_UI8, VariantChangeType, VariantClear,
15 },
16 },
17 },
18 core::{self, BSTR},
19};
20
21pub use com_shim_macro::com_shim;
22
23pub use windows::Win32::System::{Com::IDispatch, Variant::VARIANT};
24pub use windows::core::{GUID, Result};
25
26mod utils;
27
28pub trait HasIDispatch<T = Self> {
30 fn get_idispatch(&self) -> &IDispatch;
32}
33
34pub trait IDispatchExt {
36 fn call<S>(&self, name: S, args: Vec<VARIANT>) -> Result<VARIANT>
38 where
39 S: AsRef<str>;
40
41 fn get<S>(&self, name: S) -> Result<VARIANT>
43 where
44 S: AsRef<str>;
45
46 fn set<S>(&self, name: S, value: VARIANT) -> Result<VARIANT>
48 where
49 S: AsRef<str>;
50}
51
52impl IDispatchExt for IDispatch {
53 fn call<S>(&self, name: S, args: Vec<VARIANT>) -> Result<VARIANT>
54 where
55 S: AsRef<str>,
56 {
57 let iid_null = GUID::zeroed();
58 let mut result = VARIANT::null();
59 unsafe {
60 tracing::debug!("Invoking method: {}", name.as_ref());
61 self.Invoke(
62 utils::get_method_dispid(self, name)?,
63 &iid_null,
64 0,
65 DISPATCH_METHOD,
66 &utils::assemble_dispparams_get(args),
67 Some(&mut result),
68 None,
69 None,
70 )?;
71 }
72 Ok(result)
73 }
74
75 fn get<S>(&self, name: S) -> Result<VARIANT>
76 where
77 S: AsRef<str>,
78 {
79 let iid_null = GUID::zeroed();
80 let mut result = VARIANT::null();
81 unsafe {
82 self.Invoke(
83 utils::get_method_dispid(self, name)?,
84 &iid_null,
85 0,
86 DISPATCH_PROPERTYGET,
87 &DISPPARAMS::default(),
88 Some(&mut result),
89 None,
90 None,
91 )?;
92 }
93 Ok(result)
94 }
95
96 fn set<S>(&self, name: S, value: VARIANT) -> Result<VARIANT>
97 where
98 S: AsRef<str>,
99 {
100 let iid_null = GUID::zeroed();
101 let mut result = VARIANT::null();
102 unsafe {
103 self.Invoke(
104 utils::get_method_dispid(self, name)?,
105 &iid_null,
106 0,
107 DISPATCH_PROPERTYPUT,
108 &utils::assemble_dispparams_put(vec![value]),
109 Some(&mut result),
110 None,
111 None,
112 )?;
113 }
114 Ok(result)
115 }
116}
117
118pub trait VariantExt {
120 fn null() -> VARIANT;
122}
123
124impl VariantExt for VARIANT {
125 fn null() -> VARIANT {
126 let mut variant = VARIANT::default();
127 let v00 = VARIANT_0_0 {
128 vt: VT_NULL,
129 ..Default::default()
130 };
131 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
132 variant
133 }
134}
135
136pub trait VariantTypeExt<'a, T> {
138 fn variant_into(&'a self) -> core::Result<T>;
140
141 fn variant_from(value: T) -> VARIANT;
143}
144
145impl VariantTypeExt<'_, ()> for VARIANT {
146 fn variant_from(_value: ()) -> VARIANT {
147 VARIANT::null()
148 }
149
150 fn variant_into(&'_ self) -> core::Result<()> {
151 Ok(())
152 }
153}
154
155impl VariantTypeExt<'_, i16> for VARIANT {
156 fn variant_from(value: i16) -> VARIANT {
157 let mut variant = VARIANT::default();
158 let mut v00 = VARIANT_0_0 {
159 vt: VT_I2,
160 ..Default::default()
161 };
162 v00.Anonymous.iVal = value;
163 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
164 variant
165 }
166
167 fn variant_into(&self) -> core::Result<i16> {
168 unsafe {
169 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
170 let mut new = VARIANT::default();
171 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_I2)?;
172 let v00 = &new.Anonymous.Anonymous;
173 let n = v00.Anonymous.iVal;
174 VariantClear(&mut new)?;
175 Ok(n)
176 }
177 }
178}
179
180impl VariantTypeExt<'_, i32> for VARIANT {
181 fn variant_from(value: i32) -> VARIANT {
182 let mut variant = VARIANT::default();
183 let mut v00 = VARIANT_0_0 {
184 vt: VT_I4,
185 ..Default::default()
186 };
187 v00.Anonymous.lVal = value;
188 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
189 variant
190 }
191
192 fn variant_into(&self) -> core::Result<i32> {
193 unsafe {
194 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
195 let mut new = VARIANT::default();
196 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_I4)?;
197 let v00 = &new.Anonymous.Anonymous;
198 let n = v00.Anonymous.lVal;
199 VariantClear(&mut new)?;
200 Ok(n)
201 }
202 }
203}
204
205impl VariantTypeExt<'_, i64> for VARIANT {
206 fn variant_from(value: i64) -> VARIANT {
207 let mut variant = VARIANT::default();
208 let mut v00 = VARIANT_0_0 {
209 vt: VT_I8,
210 ..Default::default()
211 };
212 v00.Anonymous.llVal = value;
213 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
214 variant
215 }
216
217 fn variant_into(&self) -> core::Result<i64> {
218 unsafe {
219 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
220 let mut new = VARIANT::default();
221 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_I8)?;
222 let v00 = &new.Anonymous.Anonymous;
223 let n = v00.Anonymous.llVal;
224 VariantClear(&mut new)?;
225 Ok(n)
226 }
227 }
228}
229
230impl VariantTypeExt<'_, u8> for VARIANT {
231 fn variant_from(value: u8) -> VARIANT {
232 let mut variant = VARIANT::default();
233 let mut v00 = VARIANT_0_0 {
234 vt: VT_UI1,
235 ..Default::default()
236 };
237 v00.Anonymous.bVal = value;
238 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
239 variant
240 }
241
242 fn variant_into(&self) -> core::Result<u8> {
243 unsafe {
244 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
245 let mut new = VARIANT::default();
246 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_UI1)?;
247 let v00 = &new.Anonymous.Anonymous;
248 let n = v00.Anonymous.bVal;
249 VariantClear(&mut new)?;
250 Ok(n)
251 }
252 }
253}
254
255impl VariantTypeExt<'_, u16> for VARIANT {
256 fn variant_from(value: u16) -> VARIANT {
257 let mut variant = VARIANT::default();
258 let mut v00 = VARIANT_0_0 {
259 vt: VT_UI2,
260 ..Default::default()
261 };
262 v00.Anonymous.uiVal = value;
263 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
264 variant
265 }
266
267 fn variant_into(&self) -> core::Result<u16> {
268 unsafe {
269 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
270 let mut new = VARIANT::default();
271 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_UI2)?;
272 let v00 = &new.Anonymous.Anonymous;
273 let n = v00.Anonymous.uiVal;
274 VariantClear(&mut new)?;
275 Ok(n)
276 }
277 }
278}
279
280impl VariantTypeExt<'_, u32> for VARIANT {
281 fn variant_from(value: u32) -> VARIANT {
282 let mut variant = VARIANT::default();
283 let mut v00 = VARIANT_0_0 {
284 vt: VT_UI4,
285 ..Default::default()
286 };
287 v00.Anonymous.ulVal = value;
288 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
289 variant
290 }
291
292 fn variant_into(&self) -> core::Result<u32> {
293 unsafe {
294 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
295 let mut new = VARIANT::default();
296 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_UI4)?;
297 let v00 = &new.Anonymous.Anonymous;
298 let n = v00.Anonymous.ulVal;
299 VariantClear(&mut new)?;
300 Ok(n)
301 }
302 }
303}
304
305impl VariantTypeExt<'_, u64> for VARIANT {
306 fn variant_from(value: u64) -> VARIANT {
307 let mut variant = VARIANT::default();
308 let mut v00 = VARIANT_0_0 {
309 vt: VT_UI8,
310 ..Default::default()
311 };
312 v00.Anonymous.ullVal = value;
313 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
314 variant
315 }
316
317 fn variant_into(&self) -> core::Result<u64> {
318 unsafe {
319 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
320 let mut new = VARIANT::default();
321 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_UI8)?;
322 let v00 = &new.Anonymous.Anonymous;
323 let n = v00.Anonymous.ullVal;
324 VariantClear(&mut new)?;
325 Ok(n)
326 }
327 }
328}
329
330impl VariantTypeExt<'_, String> for VARIANT {
331 fn variant_from(value: String) -> VARIANT {
332 let mut variant = VARIANT::default();
333 let mut v00 = VARIANT_0_0 {
334 vt: VT_BSTR,
335 ..Default::default()
336 };
337 let bstr = BSTR::from(&value);
338 v00.Anonymous.bstrVal = ManuallyDrop::new(bstr);
339 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
340 variant
341 }
342
343 fn variant_into(&self) -> core::Result<String> {
344 unsafe {
345 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
346 let mut new = VARIANT::default();
347 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_BSTR)?;
348 let v00 = &new.Anonymous.Anonymous;
349 let str = v00.Anonymous.bstrVal.to_string();
350 VariantClear(&mut new)?;
351 Ok(str)
352 }
353 }
354}
355
356impl VariantTypeExt<'_, bool> for VARIANT {
357 fn variant_from(value: bool) -> VARIANT {
358 let mut variant = VARIANT::default();
359 let mut v00 = VARIANT_0_0 {
360 vt: VT_BOOL,
361 ..Default::default()
362 };
363 v00.Anonymous.boolVal = VARIANT_BOOL::from(value);
364 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
365 variant
366 }
367
368 fn variant_into(&self) -> core::Result<bool> {
369 unsafe {
370 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
371 let mut new = VARIANT::default();
372 VariantChangeType(&mut new, self, VAR_CHANGE_FLAGS(0), VT_BOOL)?;
373 let v00 = &new.Anonymous.Anonymous;
374 let b = v00.Anonymous.boolVal.as_bool();
375 VariantClear(&mut new)?;
376 Ok(b)
377 }
378 }
379}
380
381impl<'a> VariantTypeExt<'a, &'a IDispatch> for VARIANT {
382 fn variant_from(value: &'a IDispatch) -> VARIANT {
383 let mut variant = VARIANT::default();
384 let mut v00 = VARIANT_0_0 {
385 vt: VT_DISPATCH,
386 ..Default::default()
387 };
388 v00.Anonymous.pdispVal = ManuallyDrop::new(Some(value.clone()));
389 variant.Anonymous.Anonymous = ManuallyDrop::new(v00);
390 variant
391 }
392
393 fn variant_into(&'a self) -> core::Result<&'a IDispatch> {
394 unsafe {
395 tracing::debug!("Own type: {:?}", self.Anonymous.Anonymous.vt);
396 let v00 = &self.Anonymous.Anonymous;
397 let idisp = v00.Anonymous.pdispVal.as_ref().ok_or(core::Error::new(
398 core::HRESULT(0x00123456),
399 core::HSTRING::from("com-shim: Cannot read IDispatch"),
400 ))?;
401 Ok(idisp)
402 }
403 }
404}