com_shim/
lib.rs

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
28/// A component that has an IDispatch value. Every component needs this, and this trait guarantees that.
29pub trait HasIDispatch<T = Self> {
30    /// Get the IDispatch object for low-level access to this component.
31    fn get_idispatch(&self) -> &IDispatch;
32}
33
34/// Additional functions for working with an [`IDispatch`].
35pub trait IDispatchExt {
36    /// Call a function on this IDispatch
37    fn call<S>(&self, name: S, args: Vec<VARIANT>) -> Result<VARIANT>
38    where
39        S: AsRef<str>;
40
41    /// Get the value of a variable on this IDispatch
42    fn get<S>(&self, name: S) -> Result<VARIANT>
43    where
44        S: AsRef<str>;
45
46    /// Set a value of a variable on this IDispatch
47    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
118/// Extension functions for a [`VARIANT`].
119pub trait VariantExt {
120    /// Generate a null [`VARIANT`].
121    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
136/// Functions to convert to and from a type that can be stored in a [`VARIANT`].
137pub trait VariantTypeExt<'a, T> {
138    /// Convert from a [`VARIANT`] into a type, T.
139    fn variant_into(&'a self) -> core::Result<T>;
140
141    /// Convert from a type T into a [`VARIANT`].
142    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}