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