]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/automtn.cpp
don't generate wxEVT_CONTEXT_MENU messages for right clicks in the list control header
[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 #include "wx/defs.h"
20
21 // Watcom C++ gives a linker error if this is compiled in.
22 // With Borland C++, all samples crash if this is compiled in.
23 #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
24
25 #define _FORCENAMELESSUNION
26 #include "wx/log.h"
27 #include "wx/msw/private.h"
28 #include "wx/msw/ole/oleutils.h"
29 #include "wx/msw/ole/automtn.h"
30 #include "wx/math.h"
31
32 #ifdef __WXWINCE__
33 #include "wx/msw/wince/time.h"
34 #else
35 #include <time.h>
36 #endif
37
38 #include <wtypes.h>
39 #include <unknwn.h>
40
41 #include <ole2.h>
42 #define _huge
43
44 #ifndef __WXWINCE__
45 #include <ole2ver.h>
46 #endif
47
48 #include <oleauto.h>
49
50 #if wxUSE_DATETIME
51 #include "wx/datetime.h"
52 #endif // wxUSE_TIMEDATE
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 {
64 m_dispatchPtr = dispatchPtr;
65 }
66
67 wxAutomationObject::~wxAutomationObject()
68 {
69 if (m_dispatchPtr)
70 {
71 ((IDispatch*)m_dispatchPtr)->Release();
72 m_dispatchPtr = NULL;
73 }
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 {
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())
110 {
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;
169 delete[] oleArgs;
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,
182 (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
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);
221 }
222 }
223 return true;
224 }
225
226 // Invoke a member function
227 wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[])
228 {
229 wxVariant retVariant;
230 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args))
231 {
232 retVariant.MakeNull();
233 }
234 return retVariant;
235 }
236
237 wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args)
238 {
239 wxVariant retVariant;
240 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args))
241 {
242 retVariant.MakeNull();
243 }
244 return retVariant;
245 }
246
247 wxVariant wxAutomationObject::CallMethod(const wxString& member,
248 const wxVariant& arg1, const wxVariant& arg2,
249 const wxVariant& arg3, const wxVariant& arg4,
250 const wxVariant& arg5, const wxVariant& arg6)
251 {
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;
291 }
292
293 // Get/Set property
294 wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const
295 {
296 wxVariant retVariant;
297 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
298 {
299 retVariant.MakeNull();
300 }
301 return retVariant;
302 }
303 wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const
304 {
305 wxVariant retVariant;
306 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
307 {
308 retVariant.MakeNull();
309 }
310 return retVariant;
311 }
312
313 wxVariant wxAutomationObject::GetProperty(const wxString& property,
314 const wxVariant& arg1, const wxVariant& arg2,
315 const wxVariant& arg3, const wxVariant& arg4,
316 const wxVariant& arg5, const wxVariant& arg6)
317 {
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;
357 }
358
359 bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[])
360 {
361 wxVariant retVariant;
362 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args))
363 {
364 return false;
365 }
366 return true;
367 }
368
369 bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args)
370 {
371 wxVariant retVariant;
372 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args))
373 {
374 return false;
375 }
376 return true;
377 }
378
379 bool wxAutomationObject::PutProperty(const wxString& property,
380 const wxVariant& arg1, const wxVariant& arg2,
381 const wxVariant& arg3, const wxVariant& arg4,
382 const wxVariant& arg5, const wxVariant& arg6)
383 {
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;
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 {
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;
439 }
440
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 {
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;
457 }
458
459
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 {
463 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
464 if (dispatch)
465 {
466 obj.SetDispatchPtr(dispatch);
467 return true;
468 }
469 else
470 return false;
471 }
472
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 {
476 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
477 if (dispatch)
478 {
479 obj.SetDispatchPtr(dispatch);
480 return true;
481 }
482 else
483 return false;
484 }
485
486 // Get a dispatch pointer from the current object associated
487 // with a class id
488 bool wxAutomationObject::GetInstance(const wxString& classId) const
489 {
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;
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 {
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;
544 }
545
546
547 WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
548 {
549 ClearVariant(&oleVariant);
550 if (variant.IsNull())
551 {
552 oleVariant.vt = VT_NULL;
553 return true;
554 }
555
556 wxString type(variant.GetType());
557
558
559 if (type == wxT("long"))
560 {
561 oleVariant.vt = VT_I4;
562 oleVariant.lVal = variant.GetLong() ;
563 }
564 // cVal not always present
565 #ifndef __GNUWIN32__
566 else if (type == wxT("char"))
567 {
568 oleVariant.vt=VT_I1; // Signed Char
569 oleVariant.cVal=variant.GetChar();
570 }
571 #endif
572 else if (type == wxT("double"))
573 {
574 oleVariant.vt = VT_R8;
575 oleVariant.dblVal = variant.GetDouble();
576 }
577 else if (type == wxT("bool"))
578 {
579 oleVariant.vt = VT_BOOL;
580 // 'bool' required for VC++ 4 apparently
581 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
582 oleVariant.bool = variant.GetBool();
583 #else
584 oleVariant.boolVal = variant.GetBool();
585 #endif
586 }
587 else if (type == wxT("string"))
588 {
589 wxString str( variant.GetString() );
590 oleVariant.vt = VT_BSTR;
591 oleVariant.bstrVal = wxConvertStringToOle(str);
592 }
593 #if wxUSE_DATETIME
594 else if (type == wxT("datetime"))
595 {
596 wxDateTime date( variant.GetDateTime() );
597 oleVariant.vt = VT_DATE;
598
599 long dosDateTime = date.GetAsDOS();
600 short dosDate = short((dosDateTime & 0xFFFF0000) >> 16);
601 short dosTime = short(dosDateTime & 0xFFFF);
602
603 DosDateTimeToVariantTime(dosDate, dosTime, & oleVariant.date);
604 }
605 #endif
606 else if (type == wxT("void*"))
607 {
608 oleVariant.vt = VT_DISPATCH;
609 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
610 }
611 else if (type == wxT("list") || type == wxT("stringlist"))
612 {
613 oleVariant.vt = VT_VARIANT | VT_ARRAY;
614
615 SAFEARRAY *psa;
616 SAFEARRAYBOUND saBound;
617 VARIANTARG *pvargBase;
618 VARIANTARG *pvarg;
619 int i, j;
620
621 int iCount = variant.GetCount();
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
636 wxVariant eachVariant(variant[i]);
637 if (!wxConvertVariantToOle(eachVariant, * pvarg))
638 {
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);
654
655 oleVariant.parray = psa;
656 }
657 else
658 {
659 oleVariant.vt = VT_NULL;
660 return false;
661 }
662 return true;
663 }
664
665 #ifndef VT_TYPEMASK
666 #define VT_TYPEMASK 0xfff
667 #endif
668
669 WXDLLEXPORT bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
670 {
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 {
681 #if wxUSE_DATETIME
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);
689 variant = date;
690 #endif
691 break;
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 {
706 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC
707 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
708 variant = (long) (oleVariant.bool != 0);
709 #else
710 variant = (bool) (oleVariant.bool != 0);
711 #endif
712 #else
713 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
714 variant = (long) (oleVariant.boolVal != 0);
715 #else
716 variant = (bool) (oleVariant.boolVal != 0);
717 #endif
718 #endif
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;
776 }
777
778 /*
779 * ClearVariant
780 *
781 * Zeros a variant structure without regard to current contents
782 */
783 static void ClearVariant(VARIANTARG *pvarg)
784 {
785 pvarg->vt = VT_EMPTY;
786 pvarg->wReserved1 = 0;
787 pvarg->wReserved2 = 0;
788 pvarg->wReserved3 = 0;
789 pvarg->lVal = 0;
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 {
800 VARTYPE vt;
801 VARIANTARG _huge *pvargArray;
802 long lLBound, lUBound, l;
803
804 vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags
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_I4:
855 case VT_BOOL:
856 case VT_R8:
857 case VT_ERROR: // to avoid erroring on an error return from Excel
858 case VT_EMPTY:
859 // no work for these types
860 break;
861
862 default:
863 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
864 break;
865 }
866 }
867
868 ClearVariant(pvarg);
869 }
870
871 #if 0
872
873 void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr)
874 {
875 TCHAR szBuf[512];
876
877 switch (GetScode(hr))
878 {
879 case DISP_E_UNKNOWNNAME:
880 wsprintf(szBuf, L"%s: Unknown name or named argument.", szMember);
881 break;
882
883 case DISP_E_BADPARAMCOUNT:
884 wsprintf(szBuf, L"%s: Incorrect number of arguments.", szMember);
885 break;
886
887 case DISP_E_EXCEPTION:
888 wsprintf(szBuf, L"%s: Error %d: ", szMember, pexcep->wCode);
889 if (pexcep->bstrDescription != NULL)
890 lstrcat(szBuf, pexcep->bstrDescription);
891 else
892 lstrcat(szBuf, L"<<No Description>>");
893 break;
894
895 case DISP_E_MEMBERNOTFOUND:
896 wsprintf(szBuf, L"%s: method or property not found.", szMember);
897 break;
898
899 case DISP_E_OVERFLOW:
900 wsprintf(szBuf, L"%s: Overflow while coercing argument values.", szMember);
901 break;
902
903 case DISP_E_NONAMEDARGS:
904 wsprintf(szBuf, L"%s: Object implementation does not support named arguments.",
905 szMember);
906 break;
907
908 case DISP_E_UNKNOWNLCID:
909 wsprintf(szBuf, L"%s: The locale ID is unknown.", szMember);
910 break;
911
912 case DISP_E_PARAMNOTOPTIONAL:
913 wsprintf(szBuf, L"%s: Missing a required parameter.", szMember);
914 break;
915
916 case DISP_E_PARAMNOTFOUND:
917 wsprintf(szBuf, L"%s: Argument not found, argument %d.", szMember, uiArgErr);
918 break;
919
920 case DISP_E_TYPEMISMATCH:
921 wsprintf(szBuf, L"%s: Type mismatch, argument %d.", szMember, uiArgErr);
922 break;
923
924 default:
925 wsprintf(szBuf, L"%s: Unknown error occurred.", szMember);
926 break;
927 }
928
929 wxLogWarning(szBuf);
930 }
931
932 #endif
933
934 #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)