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