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