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