win_idispatch/
dispatch.rs1use std::{convert::TryFrom, ptr};
2
3use log::trace;
4use widestring::WideCString;
5use winapi::{shared::{guiddef::IID_NULL, minwindef::{UINT, WORD}, winerror::NOERROR, wtypes::{VT_ARRAY, VT_SAFEARRAY}}, um::{
6 oaidl::{DISPID, DISPID_PROPERTYPUT, DISPPARAMS, EXCEPINFO, LPDISPATCH, VARIANT},
7 oleauto::{
8 VariantClear, VariantInit, DISPATCH_METHOD, DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT,
9 },
10 winnls::GetUserDefaultLCID,
11 }};
12
13use win_variant::{free_variant, free_variants, VariantArg, VariantResult};
14
15use super::Error;
16
17#[derive(PartialEq)]
18enum DispatchOperation {
19 Method,
20 GetProperty,
21 PutProperty,
22}
23
24impl From<DispatchOperation> for WORD {
25 fn from(value: DispatchOperation) -> WORD {
26 match value {
27 DispatchOperation::Method => DISPATCH_METHOD,
28 DispatchOperation::GetProperty => DISPATCH_PROPERTYGET,
29 DispatchOperation::PutProperty => DISPATCH_PROPERTYPUT,
30 }
31 }
32}
33
34pub struct DispatchInterface {
37 dispatch: LPDISPATCH,
38 released: bool,
39}
40
41impl DispatchInterface {
42 pub fn new(dispatch: LPDISPATCH) -> DispatchInterface {
45 DispatchInterface {
46 dispatch,
47 released: false,
48 }
49 }
50
51 fn get_ids_of_name(&self, name: &str) -> Result<DISPID, Error> {
52 let mut wide: Vec<u16> = WideCString::from_str(name)?.into_vec();
53 let mut names = vec![wide.as_mut_ptr()];
54 let mut id: DISPID = 0;
55 let result = unsafe {
56 if let Some(r) = self.dispatch.as_ref() {
57 r.GetIDsOfNames(
58 &IID_NULL,
59 names.as_mut_ptr(),
60 1,
61 GetUserDefaultLCID(),
62 &mut id,
63 )
64 } else {
65 return Err(Error::NullDispatchPointer);
66 }
67 };
68 if result != NOERROR {
69 return Err(result.into());
70 }
71 Ok(id)
72 }
73
74 fn invoke(
75 &self,
76 operation: DispatchOperation,
77 name: &str,
78 args: Option<Vec<VariantArg>>,
79 ) -> Result<VARIANT, Error> {
80 let command_id = self.get_ids_of_name(name)?;
81 let mut args: Option<Vec<VARIANT>> = match args {
82 Some(mut args) => {
83 args.reverse();
85 Some(args.into_iter().map(|a| a.into()).collect())
86 }
87 None => None,
88 };
89 let mut params: DISPPARAMS = DISPPARAMS::default();
90 if let Some(args) = args.as_mut() {
91 params.cArgs = args.len() as UINT;
92 params.rgvarg = &mut args[0];
93 }
94 let mut named_params = if operation == DispatchOperation::PutProperty {
95 Some(vec![DISPID_PROPERTYPUT])
96 } else {
97 None
98 };
99 if let Some(named_params) = named_params.as_mut() {
100 params.rgdispidNamedArgs = &mut named_params[0];
101 params.cNamedArgs = named_params.len() as UINT;
102 }
103
104 let mut result: VARIANT = VARIANT::default();
105 unsafe { VariantInit(&mut result) };
106
107 let mut expect = EXCEPINFO::default();
108
109 let mut arg_error: UINT = 0;
110 let hr = unsafe {
111 if let Some(r) = self.dispatch.as_ref() {
112 r.Invoke(
113 command_id,
114 &IID_NULL,
115 GetUserDefaultLCID(),
116 operation.into(),
117 &mut params,
118 &mut result,
119 &mut expect,
120 &mut arg_error,
121 )
122 } else {
123 VariantClear(&mut result);
124 if let Some(args) = args.as_mut() {
125 free_variants(args);
126 }
127 return Err(Error::NullDispatchPointer);
128 }
129 };
130 if let Some(args) = args.as_mut() {
131 free_variants(args);
132 }
133 if hr != NOERROR {
134 return Err(hr.into());
135 }
136 Ok(result)
137 }
138 pub fn call(&self, name: &str, args: Option<Vec<VariantArg>>) -> Result<VariantResult, Error> {
141 match self.invoke(DispatchOperation::Method, name, args) {
142 Err(e) => Err(e),
143 Ok(mut v) => {
144 let result = VariantResult::try_from(v);
145 unsafe {
146 let vt = v.n1.n2().vt as u32;
147 if vt != VT_SAFEARRAY && vt&VT_ARRAY == 0 {
148 free_variant(&mut v);
149 }
150 }
151 Ok(result?)
152 }
153 }
154 }
155
156 pub fn get(&self, name: &str, args: Option<Vec<VariantArg>>) -> Result<VariantResult, Error> {
159 match self.invoke(DispatchOperation::GetProperty, name, args) {
160 Err(e) => Err(e),
161 Ok(mut v) => {
162 let result = VariantResult::try_from(v);
163 unsafe {
164 let vt = v.n1.n2().vt as u32;
165 if vt != VT_SAFEARRAY && vt&VT_ARRAY == 0 {
166 free_variant(&mut v);
167 }
168 }
169 Ok(result?)
170 }
171 }
172 }
173 pub fn put(&self, name: &str, args: Option<Vec<VariantArg>>) -> Result<VariantResult, Error> {
176 match self.invoke(DispatchOperation::PutProperty, name, args) {
177 Err(e) => Err(e),
178 Ok(mut v) => {
179 let result = VariantResult::try_from(v);
180 unsafe {
181 let vt = v.n1.n2().vt as u32;
182 if vt != VT_SAFEARRAY && vt&VT_ARRAY == 0 {
183 free_variant(&mut v);
184 }
185 }
186 Ok(result?)
187 }
188 }
189 }
190
191 fn release(&mut self) {
192 if self.released {
193 return;
194 }
195 unsafe {
196 if let Some(r) = self.dispatch.as_ref() {
197 r.Release();
198 }
199 self.released = true;
200 self.dispatch = ptr::null_mut();
201 }
202 }
203}
204
205impl Drop for DispatchInterface {
206 fn drop(&mut self) {
207 trace!("dropping Dispatch interface");
208 self.release();
209 }
210}