]>
Commit | Line | Data |
---|---|---|
d980b3e1 JS |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: automtn.cpp | |
3 | // Purpose: OLE automation utilities | |
4 | // Author: Julian Smart | |
5 | // Modified by: | |
6 | // Created: 11/6/98 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 1998, Julian Smart | |
65571936 | 9 | // Licence: wxWindows licence |
d980b3e1 JS |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
d980b3e1 JS |
12 | // For compilers that support precompilation, includes "wx.h". |
13 | #include "wx/wxprec.h" | |
14 | ||
15 | #if defined(__BORLANDC__) | |
16 | #pragma hdrstop | |
17 | #endif | |
18 | ||
f6bcfd97 | 19 | #include "wx/defs.h" |
d980b3e1 | 20 | |
457e6c54 | 21 | // Watcom C++ gives a linker error if this is compiled in. |
f6bcfd97 | 22 | // With Borland C++, all samples crash if this is compiled in. |
6b12494d | 23 | #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__) |
457e6c54 | 24 | |
5283098e | 25 | #define _FORCENAMELESSUNION |
f6bcfd97 | 26 | #include "wx/log.h" |
4676948b | 27 | #include "wx/msw/private.h" |
ed5317e5 | 28 | #include "wx/msw/ole/oleutils.h" |
42e69d6b | 29 | #include "wx/msw/ole/automtn.h" |
b713f891 | 30 | #include "wx/math.h" |
4676948b JS |
31 | |
32 | #ifdef __WXWINCE__ | |
33 | #include "wx/msw/wince/time.h" | |
34 | #else | |
f6bcfd97 | 35 | #include <time.h> |
4676948b | 36 | #endif |
f6bcfd97 | 37 | |
7dee726c RS |
38 | #include <wtypes.h> |
39 | #include <unknwn.h> | |
4676948b | 40 | |
7dee726c RS |
41 | #include <ole2.h> |
42 | #define _huge | |
4676948b JS |
43 | |
44 | #ifndef __WXWINCE__ | |
42e69d6b | 45 | #include <ole2ver.h> |
4676948b JS |
46 | #endif |
47 | ||
42e69d6b | 48 | #include <oleauto.h> |
17b74d79 | 49 | |
61bfe4b0 JS |
50 | #if wxUSE_DATETIME |
51 | #include "wx/datetime.h" | |
e421922f | 52 | #endif // wxUSE_TIMEDATE |
d980b3e1 JS |
53 | |
54 | static void ClearVariant(VARIANTARG *pvarg) ; | |
55 | static void ReleaseVariant(VARIANTARG *pvarg) ; | |
56 | // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr); | |
57 | ||
58 | /* | |
59 | * wxAutomationObject | |
60 | */ | |
61 | ||
62 | wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr) | |
63 | { | |
0a0e6a5b | 64 | m_dispatchPtr = dispatchPtr; |
d980b3e1 JS |
65 | } |
66 | ||
67 | wxAutomationObject::~wxAutomationObject() | |
68 | { | |
0a0e6a5b WS |
69 | if (m_dispatchPtr) |
70 | { | |
71 | ((IDispatch*)m_dispatchPtr)->Release(); | |
72 | m_dispatchPtr = NULL; | |
73 | } | |
d980b3e1 JS |
74 | } |
75 | ||
76 | #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i])) | |
77 | ||
78 | // For Put/Get, no named arguments are allowed. | |
79 | bool wxAutomationObject::Invoke(const wxString& member, int action, | |
80 | wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const | |
81 | { | |
0a0e6a5b WS |
82 | if (!m_dispatchPtr) |
83 | return false; | |
84 | ||
85 | // nonConstMember is necessary because the wxString class doesn't have enough consts... | |
86 | wxString nonConstMember(member); | |
87 | ||
88 | int ch = nonConstMember.Find('.'); | |
89 | if (ch != -1) | |
90 | { | |
91 | // Use dot notation to get the next object | |
92 | wxString member2(nonConstMember.Left((size_t) ch)); | |
93 | wxString rest(nonConstMember.Right(nonConstMember.Length() - ch - 1)); | |
94 | wxAutomationObject obj; | |
95 | if (!GetObject(obj, member2)) | |
96 | return false; | |
97 | return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs); | |
98 | } | |
99 | ||
100 | VARIANTARG vReturn; | |
101 | ClearVariant(& vReturn); | |
102 | ||
103 | VARIANTARG* vReturnPtr = & vReturn; | |
104 | ||
105 | // Find number of names args | |
106 | int namedArgCount = 0; | |
107 | int i; | |
108 | for (i = 0; i < noArgs; i++) | |
109 | if (!INVOKEARG(i).GetName().IsNull()) | |
12335fa6 | 110 | { |
0a0e6a5b WS |
111 | namedArgCount ++; |
112 | } | |
113 | ||
114 | int namedArgStringCount = namedArgCount + 1; | |
115 | BSTR* argNames = new BSTR[namedArgStringCount]; | |
116 | argNames[0] = wxConvertStringToOle(member); | |
117 | ||
118 | // Note that arguments are specified in reverse order | |
119 | // (all totally logical; hey, we're dealing with OLE here.) | |
120 | ||
121 | int j = 0; | |
122 | for (i = 0; i < namedArgCount; i++) | |
123 | { | |
124 | if (!INVOKEARG(i).GetName().IsNull()) | |
125 | { | |
126 | argNames[(namedArgCount-j)] = wxConvertStringToOle(INVOKEARG(i).GetName()); | |
127 | j ++; | |
128 | } | |
129 | } | |
130 | ||
131 | // + 1 for the member name, + 1 again in case we're a 'put' | |
132 | DISPID* dispIds = new DISPID[namedArgCount + 2]; | |
133 | ||
134 | HRESULT hr; | |
135 | DISPPARAMS dispparams; | |
136 | unsigned int uiArgErr; | |
137 | EXCEPINFO excep; | |
138 | ||
139 | // Get the IDs for the member and its arguments. GetIDsOfNames expects the | |
140 | // member name as the first name, followed by argument names (if any). | |
141 | hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, argNames, | |
142 | 1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, dispIds); | |
143 | if (FAILED(hr)) | |
144 | { | |
145 | // ShowException(szMember, hr, NULL, 0); | |
146 | delete[] argNames; | |
147 | delete[] dispIds; | |
148 | return false; | |
149 | } | |
150 | ||
151 | // if doing a property put(ref), we need to adjust the first argument to have a | |
152 | // named arg of DISPID_PROPERTYPUT. | |
153 | if (action & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) | |
154 | { | |
155 | namedArgCount = 1; | |
156 | dispIds[1] = DISPID_PROPERTYPUT; | |
157 | vReturnPtr = (VARIANTARG*) NULL; | |
158 | } | |
159 | ||
160 | // Convert the wxVariants to VARIANTARGs | |
161 | VARIANTARG* oleArgs = new VARIANTARG[noArgs]; | |
162 | for (i = 0; i < noArgs; i++) | |
163 | { | |
164 | // Again, reverse args | |
165 | if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i])) | |
166 | { | |
167 | delete[] argNames; | |
168 | delete[] dispIds; | |
12335fa6 | 169 | delete[] oleArgs; |
0a0e6a5b WS |
170 | return false; |
171 | } | |
172 | } | |
173 | ||
174 | dispparams.rgdispidNamedArgs = dispIds + 1; | |
175 | dispparams.rgvarg = oleArgs; | |
176 | dispparams.cArgs = noArgs; | |
177 | dispparams.cNamedArgs = namedArgCount; | |
178 | ||
179 | excep.pfnDeferredFillIn = NULL; | |
180 | ||
181 | hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT, | |
5c519b6c | 182 | (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr); |
0a0e6a5b WS |
183 | |
184 | for (i = 0; i < namedArgStringCount; i++) | |
185 | { | |
186 | SysFreeString(argNames[i]); | |
187 | } | |
188 | delete[] argNames; | |
189 | delete[] dispIds; | |
190 | ||
191 | for (i = 0; i < noArgs; i++) | |
192 | ReleaseVariant(& oleArgs[i]) ; | |
193 | delete[] oleArgs; | |
194 | ||
195 | if (FAILED(hr)) | |
196 | { | |
197 | // display the exception information if appropriate: | |
198 | // ShowException((const char*) member, hr, &excep, uiArgErr); | |
199 | ||
200 | // free exception structure information | |
201 | SysFreeString(excep.bstrSource); | |
202 | SysFreeString(excep.bstrDescription); | |
203 | SysFreeString(excep.bstrHelpFile); | |
204 | ||
205 | if (vReturnPtr) | |
206 | ReleaseVariant(vReturnPtr); | |
207 | return false; | |
208 | } | |
209 | else | |
210 | { | |
211 | if (vReturnPtr) | |
212 | { | |
213 | // Convert result to wxVariant form | |
214 | wxConvertOleToVariant(vReturn, retValue); | |
215 | // Mustn't release the dispatch pointer | |
216 | if (vReturn.vt == VT_DISPATCH) | |
217 | { | |
218 | vReturn.pdispVal = (IDispatch*) NULL; | |
219 | } | |
220 | ReleaseVariant(& vReturn); | |
12335fa6 | 221 | } |
0a0e6a5b WS |
222 | } |
223 | return true; | |
d980b3e1 JS |
224 | } |
225 | ||
226 | // Invoke a member function | |
227 | wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[]) | |
228 | { | |
0a0e6a5b WS |
229 | wxVariant retVariant; |
230 | if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args)) | |
231 | { | |
232 | retVariant.MakeNull(); | |
233 | } | |
234 | return retVariant; | |
d980b3e1 JS |
235 | } |
236 | ||
24f4ad95 JS |
237 | wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args) |
238 | { | |
0a0e6a5b WS |
239 | wxVariant retVariant; |
240 | if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args)) | |
241 | { | |
242 | retVariant.MakeNull(); | |
243 | } | |
244 | return retVariant; | |
24f4ad95 JS |
245 | } |
246 | ||
d980b3e1 | 247 | wxVariant wxAutomationObject::CallMethod(const wxString& member, |
0a0e6a5b WS |
248 | const wxVariant& arg1, const wxVariant& arg2, |
249 | const wxVariant& arg3, const wxVariant& arg4, | |
250 | const wxVariant& arg5, const wxVariant& arg6) | |
d980b3e1 | 251 | { |
0a0e6a5b WS |
252 | const wxVariant** args = new const wxVariant*[6]; |
253 | int i = 0; | |
254 | if (!arg1.IsNull()) | |
255 | { | |
256 | args[i] = & arg1; | |
257 | i ++; | |
258 | } | |
259 | if (!arg2.IsNull()) | |
260 | { | |
261 | args[i] = & arg2; | |
262 | i ++; | |
263 | } | |
264 | if (!arg3.IsNull()) | |
265 | { | |
266 | args[i] = & arg3; | |
267 | i ++; | |
268 | } | |
269 | if (!arg4.IsNull()) | |
270 | { | |
271 | args[i] = & arg4; | |
272 | i ++; | |
273 | } | |
274 | if (!arg5.IsNull()) | |
275 | { | |
276 | args[i] = & arg5; | |
277 | i ++; | |
278 | } | |
279 | if (!arg6.IsNull()) | |
280 | { | |
281 | args[i] = & arg6; | |
282 | i ++; | |
283 | } | |
284 | wxVariant retVariant; | |
285 | if (!Invoke(member, DISPATCH_METHOD, retVariant, i, NULL, args)) | |
286 | { | |
287 | retVariant.MakeNull(); | |
288 | } | |
289 | delete[] args; | |
290 | return retVariant; | |
d980b3e1 JS |
291 | } |
292 | ||
293 | // Get/Set property | |
24f4ad95 JS |
294 | wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const |
295 | { | |
0a0e6a5b WS |
296 | wxVariant retVariant; |
297 | if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args)) | |
298 | { | |
299 | retVariant.MakeNull(); | |
300 | } | |
301 | return retVariant; | |
24f4ad95 | 302 | } |
d980b3e1 JS |
303 | wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const |
304 | { | |
0a0e6a5b WS |
305 | wxVariant retVariant; |
306 | if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args)) | |
307 | { | |
308 | retVariant.MakeNull(); | |
309 | } | |
310 | return retVariant; | |
d980b3e1 JS |
311 | } |
312 | ||
313 | wxVariant wxAutomationObject::GetProperty(const wxString& property, | |
0a0e6a5b WS |
314 | const wxVariant& arg1, const wxVariant& arg2, |
315 | const wxVariant& arg3, const wxVariant& arg4, | |
316 | const wxVariant& arg5, const wxVariant& arg6) | |
d980b3e1 | 317 | { |
0a0e6a5b WS |
318 | const wxVariant** args = new const wxVariant*[6]; |
319 | int i = 0; | |
320 | if (!arg1.IsNull()) | |
321 | { | |
322 | args[i] = & arg1; | |
323 | i ++; | |
324 | } | |
325 | if (!arg2.IsNull()) | |
326 | { | |
327 | args[i] = & arg2; | |
328 | i ++; | |
329 | } | |
330 | if (!arg3.IsNull()) | |
331 | { | |
332 | args[i] = & arg3; | |
333 | i ++; | |
334 | } | |
335 | if (!arg4.IsNull()) | |
336 | { | |
337 | args[i] = & arg4; | |
338 | i ++; | |
339 | } | |
340 | if (!arg5.IsNull()) | |
341 | { | |
342 | args[i] = & arg5; | |
343 | i ++; | |
344 | } | |
345 | if (!arg6.IsNull()) | |
346 | { | |
347 | args[i] = & arg6; | |
348 | i ++; | |
349 | } | |
350 | wxVariant retVariant; | |
351 | if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, i, NULL, args)) | |
352 | { | |
353 | retVariant.MakeNull(); | |
354 | } | |
355 | delete[] args; | |
356 | return retVariant; | |
d980b3e1 JS |
357 | } |
358 | ||
359 | bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[]) | |
360 | { | |
0a0e6a5b WS |
361 | wxVariant retVariant; |
362 | if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args)) | |
363 | { | |
364 | return false; | |
365 | } | |
366 | return true; | |
d980b3e1 JS |
367 | } |
368 | ||
24f4ad95 JS |
369 | bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args) |
370 | { | |
0a0e6a5b WS |
371 | wxVariant retVariant; |
372 | if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args)) | |
373 | { | |
374 | return false; | |
375 | } | |
376 | return true; | |
24f4ad95 JS |
377 | } |
378 | ||
d980b3e1 | 379 | bool wxAutomationObject::PutProperty(const wxString& property, |
0a0e6a5b WS |
380 | const wxVariant& arg1, const wxVariant& arg2, |
381 | const wxVariant& arg3, const wxVariant& arg4, | |
382 | const wxVariant& arg5, const wxVariant& arg6) | |
d980b3e1 | 383 | { |
0a0e6a5b WS |
384 | const wxVariant** args = new const wxVariant*[6]; |
385 | int i = 0; | |
386 | if (!arg1.IsNull()) | |
387 | { | |
388 | args[i] = & arg1; | |
389 | i ++; | |
390 | } | |
391 | if (!arg2.IsNull()) | |
392 | { | |
393 | args[i] = & arg2; | |
394 | i ++; | |
395 | } | |
396 | if (!arg3.IsNull()) | |
397 | { | |
398 | args[i] = & arg3; | |
399 | i ++; | |
400 | } | |
401 | if (!arg4.IsNull()) | |
402 | { | |
403 | args[i] = & arg4; | |
404 | i ++; | |
405 | } | |
406 | if (!arg5.IsNull()) | |
407 | { | |
408 | args[i] = & arg5; | |
409 | i ++; | |
410 | } | |
411 | if (!arg6.IsNull()) | |
412 | { | |
413 | args[i] = & arg6; | |
414 | i ++; | |
415 | } | |
416 | wxVariant retVariant; | |
417 | bool ret = Invoke(property, DISPATCH_PROPERTYPUT, retVariant, i, NULL, args); | |
418 | delete[] args; | |
419 | return ret; | |
d980b3e1 JS |
420 | } |
421 | ||
422 | ||
423 | // Uses DISPATCH_PROPERTYGET | |
424 | // and returns a dispatch pointer. The calling code should call Release | |
425 | // on the pointer, though this could be implicit by constructing an wxAutomationObject | |
426 | // with it and letting the destructor call Release. | |
427 | WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, wxVariant args[]) const | |
428 | { | |
0a0e6a5b WS |
429 | wxVariant retVariant; |
430 | if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args)) | |
431 | { | |
432 | if (retVariant.GetType() == wxT("void*")) | |
433 | { | |
434 | return (WXIDISPATCH*) retVariant.GetVoidPtr(); | |
435 | } | |
436 | } | |
437 | ||
438 | return (WXIDISPATCH*) NULL; | |
d980b3e1 JS |
439 | } |
440 | ||
24f4ad95 JS |
441 | // Uses DISPATCH_PROPERTYGET |
442 | // and returns a dispatch pointer. The calling code should call Release | |
443 | // on the pointer, though this could be implicit by constructing an wxAutomationObject | |
444 | // with it and letting the destructor call Release. | |
445 | WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, const wxVariant **args) const | |
446 | { | |
0a0e6a5b WS |
447 | wxVariant retVariant; |
448 | if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args)) | |
449 | { | |
450 | if (retVariant.GetType() == wxT("void*")) | |
451 | { | |
452 | return (WXIDISPATCH*) retVariant.GetVoidPtr(); | |
453 | } | |
454 | } | |
455 | ||
456 | return (WXIDISPATCH*) NULL; | |
24f4ad95 JS |
457 | } |
458 | ||
459 | ||
d980b3e1 JS |
460 | // A way of initialising another wxAutomationObject with a dispatch object |
461 | bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, wxVariant args[]) const | |
462 | { | |
0a0e6a5b WS |
463 | WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args); |
464 | if (dispatch) | |
465 | { | |
466 | obj.SetDispatchPtr(dispatch); | |
467 | return true; | |
468 | } | |
469 | else | |
470 | return false; | |
d980b3e1 JS |
471 | } |
472 | ||
24f4ad95 JS |
473 | // A way of initialising another wxAutomationObject with a dispatch object |
474 | bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, const wxVariant **args) const | |
475 | { | |
0a0e6a5b WS |
476 | WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args); |
477 | if (dispatch) | |
478 | { | |
479 | obj.SetDispatchPtr(dispatch); | |
480 | return true; | |
481 | } | |
482 | else | |
483 | return false; | |
24f4ad95 JS |
484 | } |
485 | ||
d980b3e1 JS |
486 | // Get a dispatch pointer from the current object associated |
487 | // with a class id | |
488 | bool wxAutomationObject::GetInstance(const wxString& classId) const | |
489 | { | |
0a0e6a5b WS |
490 | if (m_dispatchPtr) |
491 | return false; | |
492 | ||
493 | CLSID clsId; | |
494 | IUnknown * pUnk = NULL; | |
495 | ||
496 | wxBasicString unicodeName(classId.mb_str()); | |
497 | ||
498 | if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId))) | |
499 | { | |
500 | wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); | |
501 | return false; | |
502 | } | |
503 | ||
504 | if (FAILED(GetActiveObject(clsId, NULL, &pUnk))) | |
505 | { | |
506 | wxLogWarning(wxT("Cannot find an active object")); | |
507 | return false; | |
508 | } | |
509 | ||
510 | if (pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr) != S_OK) | |
511 | { | |
512 | wxLogWarning(wxT("Cannot find IDispatch interface")); | |
513 | return false; | |
514 | } | |
515 | ||
516 | return true; | |
d980b3e1 JS |
517 | } |
518 | ||
519 | // Get a dispatch pointer from a new object associated | |
520 | // with the given class id | |
521 | bool wxAutomationObject::CreateInstance(const wxString& classId) const | |
522 | { | |
0a0e6a5b WS |
523 | if (m_dispatchPtr) |
524 | return false; | |
525 | ||
526 | CLSID clsId; | |
527 | ||
528 | wxBasicString unicodeName(classId.mb_str()); | |
529 | ||
530 | if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId))) | |
531 | { | |
532 | wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); | |
533 | return false; | |
534 | } | |
535 | ||
536 | // start a new copy of Excel, grab the IDispatch interface | |
537 | if (FAILED(CoCreateInstance(clsId, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&m_dispatchPtr))) | |
538 | { | |
539 | wxLogWarning(wxT("Cannot start an instance of this class.")); | |
540 | return false; | |
541 | } | |
542 | ||
543 | return true; | |
d980b3e1 JS |
544 | } |
545 | ||
546 | ||
ed5317e5 | 547 | bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant) |
d980b3e1 | 548 | { |
0a0e6a5b WS |
549 | ClearVariant(&oleVariant); |
550 | if (variant.IsNull()) | |
551 | { | |
552 | oleVariant.vt = VT_NULL; | |
553 | return true; | |
554 | } | |
d980b3e1 JS |
555 | |
556 | wxString type(variant.GetType()); | |
557 | ||
6b978929 JS |
558 | |
559 | if (type == wxT("long")) | |
d980b3e1 JS |
560 | { |
561 | oleVariant.vt = VT_I4; | |
562 | oleVariant.lVal = variant.GetLong() ; | |
563 | } | |
6b978929 JS |
564 | // cVal not always present |
565 | #ifndef __GNUWIN32__ | |
566 | else if (type == wxT("char")) | |
567 | { | |
0a0e6a5b | 568 | oleVariant.vt=VT_I1; // Signed Char |
6b978929 JS |
569 | oleVariant.cVal=variant.GetChar(); |
570 | } | |
571 | #endif | |
223d09f6 | 572 | else if (type == wxT("double")) |
d980b3e1 JS |
573 | { |
574 | oleVariant.vt = VT_R8; | |
575 | oleVariant.dblVal = variant.GetDouble(); | |
576 | } | |
223d09f6 | 577 | else if (type == wxT("bool")) |
d980b3e1 JS |
578 | { |
579 | oleVariant.vt = VT_BOOL; | |
7c5dc04f | 580 | // 'bool' required for VC++ 4 apparently |
6b12494d | 581 | #if (defined(__VISUALC__) && (__VISUALC__ <= 1000)) |
7be1f0d9 JS |
582 | oleVariant.bool = variant.GetBool(); |
583 | #else | |
d980b3e1 | 584 | oleVariant.boolVal = variant.GetBool(); |
7be1f0d9 | 585 | #endif |
d980b3e1 | 586 | } |
223d09f6 | 587 | else if (type == wxT("string")) |
d980b3e1 JS |
588 | { |
589 | wxString str( variant.GetString() ); | |
590 | oleVariant.vt = VT_BSTR; | |
ed5317e5 | 591 | oleVariant.bstrVal = wxConvertStringToOle(str); |
d980b3e1 | 592 | } |
61bfe4b0 JS |
593 | #if wxUSE_DATETIME |
594 | else if (type == wxT("datetime")) | |
595 | { | |
596 | wxDateTime date( variant.GetDateTime() ); | |
597 | oleVariant.vt = VT_DATE; | |
94113cc5 JS |
598 | |
599 | long dosDateTime = date.GetAsDOS(); | |
600 | short dosDate = (dosDateTime & 0xFFFF0000) >> 16; | |
601 | short dosTime = dosDateTime & 0xFFFF; | |
602 | ||
603 | DosDateTimeToVariantTime(dosDate, dosTime, & oleVariant.date); | |
61bfe4b0 | 604 | } |
457e6c54 | 605 | #endif |
223d09f6 | 606 | else if (type == wxT("void*")) |
d980b3e1 JS |
607 | { |
608 | oleVariant.vt = VT_DISPATCH; | |
609 | oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr(); | |
610 | } | |
223d09f6 | 611 | else if (type == wxT("list") || type == wxT("stringlist")) |
d980b3e1 JS |
612 | { |
613 | oleVariant.vt = VT_VARIANT | VT_ARRAY; | |
614 | ||
0a0e6a5b WS |
615 | SAFEARRAY *psa; |
616 | SAFEARRAYBOUND saBound; | |
617 | VARIANTARG *pvargBase; | |
618 | VARIANTARG *pvarg; | |
619 | int i, j; | |
d980b3e1 JS |
620 | |
621 | int iCount = variant.GetCount(); | |
0a0e6a5b WS |
622 | |
623 | saBound.lLbound = 0; | |
624 | saBound.cElements = iCount; | |
625 | ||
626 | psa = SafeArrayCreate(VT_VARIANT, 1, &saBound); | |
627 | if (psa == NULL) | |
628 | return false; | |
629 | ||
630 | SafeArrayAccessData(psa, (void**)&pvargBase); | |
631 | ||
632 | pvarg = pvargBase; | |
633 | for (i = 0; i < iCount; i++) | |
634 | { | |
635 | // copy each string in the list of strings | |
d980b3e1 | 636 | wxVariant eachVariant(variant[i]); |
ed5317e5 | 637 | if (!wxConvertVariantToOle(eachVariant, * pvarg)) |
d980b3e1 | 638 | { |
0a0e6a5b WS |
639 | // memory failure: back out and free strings alloc'ed up to |
640 | // now, and then the array itself. | |
641 | pvarg = pvargBase; | |
642 | for (j = 0; j < i; j++) | |
643 | { | |
644 | SysFreeString(pvarg->bstrVal); | |
645 | pvarg++; | |
646 | } | |
647 | SafeArrayDestroy(psa); | |
648 | return false; | |
649 | } | |
650 | pvarg++; | |
651 | } | |
652 | ||
653 | SafeArrayUnaccessData(psa); | |
d980b3e1 JS |
654 | |
655 | oleVariant.parray = psa; | |
656 | } | |
657 | else | |
658 | { | |
659 | oleVariant.vt = VT_NULL; | |
0a0e6a5b | 660 | return false; |
d980b3e1 | 661 | } |
0a0e6a5b | 662 | return true; |
d980b3e1 JS |
663 | } |
664 | ||
665 | #ifndef VT_TYPEMASK | |
666 | #define VT_TYPEMASK 0xfff | |
667 | #endif | |
668 | ||
ed5317e5 | 669 | bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant) |
d980b3e1 | 670 | { |
0a0e6a5b WS |
671 | switch (oleVariant.vt & VT_TYPEMASK) |
672 | { | |
673 | case VT_BSTR: | |
674 | { | |
675 | wxString str(wxConvertStringFromOle(oleVariant.bstrVal)); | |
676 | variant = str; | |
677 | break; | |
678 | } | |
679 | case VT_DATE: | |
680 | { | |
61bfe4b0 | 681 | #if wxUSE_DATETIME |
94113cc5 JS |
682 | unsigned short dosDate = 0; |
683 | unsigned short dosTime = 0; | |
684 | VariantTimeToDosDateTime(oleVariant.date, & dosDate, & dosTime); | |
685 | ||
686 | long dosDateTime = (dosDate << 16) || dosTime; | |
687 | wxDateTime date; | |
688 | date.SetFromDOS(dosDateTime); | |
0a0e6a5b | 689 | variant = date; |
f6bcfd97 | 690 | #endif |
f6bcfd97 | 691 | break; |
0a0e6a5b WS |
692 | } |
693 | case VT_I4: | |
694 | { | |
695 | variant = (long) oleVariant.lVal; | |
696 | break; | |
697 | } | |
698 | case VT_I2: | |
699 | { | |
700 | variant = (long) oleVariant.iVal; | |
701 | break; | |
702 | } | |
703 | ||
704 | case VT_BOOL: | |
705 | { | |
6b12494d | 706 | #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC |
25889d3c | 707 | #ifndef HAVE_BOOL // Can't use bool operator if no native bool type |
0a0e6a5b | 708 | variant = (long) (oleVariant.bool != 0); |
25889d3c | 709 | #else |
0a0e6a5b | 710 | variant = (bool) (oleVariant.bool != 0); |
25889d3c | 711 | #endif |
f6bcfd97 BP |
712 | #else |
713 | #ifndef HAVE_BOOL // Can't use bool operator if no native bool type | |
0a0e6a5b | 714 | variant = (long) (oleVariant.boolVal != 0); |
7be1f0d9 | 715 | #else |
0a0e6a5b | 716 | variant = (bool) (oleVariant.boolVal != 0); |
f6bcfd97 | 717 | #endif |
7be1f0d9 | 718 | #endif |
0a0e6a5b WS |
719 | break; |
720 | } | |
721 | case VT_R8: | |
722 | { | |
723 | variant = oleVariant.dblVal; | |
724 | break; | |
725 | } | |
726 | case VT_ARRAY: | |
727 | { | |
728 | variant.ClearList(); | |
729 | ||
730 | int cDims, cElements, i; | |
731 | VARIANTARG* pvdata; | |
732 | ||
733 | // Iterate the dimensions: number of elements is x*y*z | |
734 | for (cDims = 0, cElements = 1; | |
735 | cDims < oleVariant.parray->cDims; cDims ++) | |
736 | cElements *= oleVariant.parray->rgsabound[cDims].cElements; | |
737 | ||
738 | // Get a pointer to the data | |
739 | HRESULT hr = SafeArrayAccessData(oleVariant.parray, (void HUGEP* FAR*) & pvdata); | |
740 | if (hr != NOERROR) | |
741 | return false; | |
742 | // Iterate the data. | |
743 | for (i = 0; i < cElements; i++) | |
744 | { | |
745 | VARIANTARG& oleElement = pvdata[i]; | |
746 | wxVariant vElement; | |
747 | if (!wxConvertOleToVariant(oleElement, vElement)) | |
748 | return false; | |
749 | ||
750 | variant.Append(vElement); | |
751 | } | |
752 | SafeArrayUnaccessData(oleVariant.parray); | |
753 | break; | |
754 | } | |
755 | case VT_DISPATCH: | |
756 | { | |
757 | variant = (void*) oleVariant.pdispVal; | |
758 | break; | |
759 | } | |
760 | case VT_NULL: | |
761 | { | |
762 | variant.MakeNull(); | |
763 | break; | |
764 | } | |
765 | case VT_EMPTY: | |
766 | { | |
767 | break; // Ignore Empty Variant, used only during destruction of objects | |
768 | } | |
769 | default: | |
770 | { | |
771 | wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type")); | |
772 | return false; | |
773 | } | |
774 | } | |
775 | return true; | |
d980b3e1 JS |
776 | } |
777 | ||
d980b3e1 JS |
778 | /* |
779 | * ClearVariant | |
780 | * | |
781 | * Zeros a variant structure without regard to current contents | |
782 | */ | |
783 | static void ClearVariant(VARIANTARG *pvarg) | |
784 | { | |
0a0e6a5b WS |
785 | pvarg->vt = VT_EMPTY; |
786 | pvarg->wReserved1 = 0; | |
787 | pvarg->wReserved2 = 0; | |
788 | pvarg->wReserved3 = 0; | |
789 | pvarg->lVal = 0; | |
d980b3e1 JS |
790 | } |
791 | ||
792 | /* | |
793 | * ReleaseVariant | |
794 | * | |
795 | * Clears a particular variant structure and releases any external objects | |
796 | * or memory contained in the variant. Supports the data types listed above. | |
797 | */ | |
798 | static void ReleaseVariant(VARIANTARG *pvarg) | |
799 | { | |
0a0e6a5b WS |
800 | VARTYPE vt; |
801 | VARIANTARG _huge *pvargArray; | |
802 | long lLBound, lUBound, l; | |
803 | ||
5c519b6c | 804 | vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags |
0a0e6a5b WS |
805 | |
806 | // check if an array. If so, free its contents, then the array itself. | |
807 | if (V_ISARRAY(pvarg)) | |
808 | { | |
809 | // variant arrays are all this routine currently knows about. Since a | |
810 | // variant can contain anything (even other arrays), call ourselves | |
811 | // recursively. | |
812 | if (vt == VT_VARIANT) | |
813 | { | |
814 | SafeArrayGetLBound(pvarg->parray, 1, &lLBound); | |
815 | SafeArrayGetUBound(pvarg->parray, 1, &lUBound); | |
816 | ||
817 | if (lUBound > lLBound) | |
818 | { | |
819 | lUBound -= lLBound; | |
820 | ||
821 | SafeArrayAccessData(pvarg->parray, (void**)&pvargArray); | |
822 | ||
823 | for (l = 0; l < lUBound; l++) | |
824 | { | |
825 | ReleaseVariant(pvargArray); | |
826 | pvargArray++; | |
827 | } | |
828 | ||
829 | SafeArrayUnaccessData(pvarg->parray); | |
830 | } | |
831 | } | |
832 | else | |
833 | { | |
834 | wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type")); | |
835 | } | |
836 | ||
837 | // Free the array itself. | |
838 | SafeArrayDestroy(pvarg->parray); | |
839 | } | |
840 | else | |
841 | { | |
842 | switch (vt) | |
843 | { | |
844 | case VT_DISPATCH: | |
845 | if (pvarg->pdispVal) | |
846 | pvarg->pdispVal->Release(); | |
847 | break; | |
848 | ||
849 | case VT_BSTR: | |
850 | SysFreeString(pvarg->bstrVal); | |
851 | break; | |
852 | ||
853 | case VT_I2: | |
854 | case VT_BOOL: | |
855 | case VT_R8: | |
856 | case VT_ERROR: // to avoid erroring on an error return from Excel | |
857 | // no work for these types | |
858 | break; | |
859 | ||
860 | default: | |
861 | wxLogWarning(wxT("ReleaseVariant: Unknown type")); | |
862 | break; | |
863 | } | |
864 | } | |
865 | ||
866 | ClearVariant(pvarg); | |
d980b3e1 JS |
867 | } |
868 | ||
869 | #if 0 | |
870 | ||
871 | void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr) | |
872 | { | |
0a0e6a5b WS |
873 | TCHAR szBuf[512]; |
874 | ||
875 | switch (GetScode(hr)) | |
876 | { | |
877 | case DISP_E_UNKNOWNNAME: | |
878 | wsprintf(szBuf, L"%s: Unknown name or named argument.", szMember); | |
879 | break; | |
880 | ||
881 | case DISP_E_BADPARAMCOUNT: | |
882 | wsprintf(szBuf, L"%s: Incorrect number of arguments.", szMember); | |
883 | break; | |
884 | ||
885 | case DISP_E_EXCEPTION: | |
886 | wsprintf(szBuf, L"%s: Error %d: ", szMember, pexcep->wCode); | |
887 | if (pexcep->bstrDescription != NULL) | |
888 | lstrcat(szBuf, pexcep->bstrDescription); | |
889 | else | |
890 | lstrcat(szBuf, L"<<No Description>>"); | |
891 | break; | |
892 | ||
893 | case DISP_E_MEMBERNOTFOUND: | |
894 | wsprintf(szBuf, L"%s: method or property not found.", szMember); | |
895 | break; | |
896 | ||
897 | case DISP_E_OVERFLOW: | |
898 | wsprintf(szBuf, L"%s: Overflow while coercing argument values.", szMember); | |
899 | break; | |
900 | ||
901 | case DISP_E_NONAMEDARGS: | |
902 | wsprintf(szBuf, L"%s: Object implementation does not support named arguments.", | |
903 | szMember); | |
904 | break; | |
905 | ||
906 | case DISP_E_UNKNOWNLCID: | |
907 | wsprintf(szBuf, L"%s: The locale ID is unknown.", szMember); | |
908 | break; | |
909 | ||
910 | case DISP_E_PARAMNOTOPTIONAL: | |
911 | wsprintf(szBuf, L"%s: Missing a required parameter.", szMember); | |
912 | break; | |
913 | ||
914 | case DISP_E_PARAMNOTFOUND: | |
915 | wsprintf(szBuf, L"%s: Argument not found, argument %d.", szMember, uiArgErr); | |
916 | break; | |
917 | ||
918 | case DISP_E_TYPEMISMATCH: | |
919 | wsprintf(szBuf, L"%s: Type mismatch, argument %d.", szMember, uiArgErr); | |
920 | break; | |
921 | ||
922 | default: | |
3103e8a9 | 923 | wsprintf(szBuf, L"%s: Unknown error occurred.", szMember); |
0a0e6a5b WS |
924 | break; |
925 | } | |
926 | ||
927 | wxLogWarning(szBuf); | |
d980b3e1 JS |
928 | } |
929 | ||
930 | #endif | |
931 | ||
6b12494d | 932 | #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__) |
457e6c54 | 933 |