]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/automtn.cpp
split wxEVT_GRID_CELL_CHANGE into wxEVT_GRID_CELL_CHANGING/ED pair for consistency...
[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
f6bcfd97 19// With Borland C++, all samples crash if this is compiled in.
ca5c6ac3
VZ
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
457e6c54 26
e4db172a
WS
27#ifndef WX_PRECOMP
28 #include "wx/log.h"
18680f86 29 #include "wx/math.h"
e4db172a
WS
30#endif
31
5283098e 32#define _FORCENAMELESSUNION
4676948b 33#include "wx/msw/private.h"
ed5317e5 34#include "wx/msw/ole/oleutils.h"
42e69d6b 35#include "wx/msw/ole/automtn.h"
4676948b
JS
36
37#ifdef __WXWINCE__
38#include "wx/msw/wince/time.h"
39#else
f6bcfd97 40#include <time.h>
4676948b 41#endif
f6bcfd97 42
7dee726c
RS
43#include <wtypes.h>
44#include <unknwn.h>
4676948b 45
7dee726c
RS
46#include <ole2.h>
47#define _huge
4676948b
JS
48
49#ifndef __WXWINCE__
42e69d6b 50#include <ole2ver.h>
4676948b
JS
51#endif
52
42e69d6b 53#include <oleauto.h>
17b74d79 54
61bfe4b0
JS
55#if wxUSE_DATETIME
56#include "wx/datetime.h"
b0f76951 57#endif // wxUSE_DATETIME
d980b3e1
JS
58
59static void ClearVariant(VARIANTARG *pvarg) ;
60static void ReleaseVariant(VARIANTARG *pvarg) ;
61// static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
62
63/*
64 * wxAutomationObject
65 */
66
67wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr)
68{
0a0e6a5b 69 m_dispatchPtr = dispatchPtr;
d980b3e1
JS
70}
71
72wxAutomationObject::~wxAutomationObject()
73{
0a0e6a5b
WS
74 if (m_dispatchPtr)
75 {
76 ((IDispatch*)m_dispatchPtr)->Release();
77 m_dispatchPtr = NULL;
78 }
d980b3e1
JS
79}
80
81#define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
82
83// For Put/Get, no named arguments are allowed.
84bool wxAutomationObject::Invoke(const wxString& member, int action,
85 wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const
86{
0a0e6a5b
WS
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));
e4db172a 98 wxString rest(nonConstMember.Right(nonConstMember.length() - ch - 1));
0a0e6a5b
WS
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())
12335fa6 115 {
0a0e6a5b
WS
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;
12335fa6 174 delete[] oleArgs;
0a0e6a5b
WS
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,
5c519b6c 187 (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
0a0e6a5b
WS
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);
12335fa6 226 }
0a0e6a5b
WS
227 }
228 return true;
d980b3e1
JS
229}
230
231// Invoke a member function
232wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[])
233{
0a0e6a5b
WS
234 wxVariant retVariant;
235 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args))
236 {
237 retVariant.MakeNull();
238 }
239 return retVariant;
d980b3e1
JS
240}
241
24f4ad95
JS
242wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args)
243{
0a0e6a5b
WS
244 wxVariant retVariant;
245 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args))
246 {
247 retVariant.MakeNull();
248 }
249 return retVariant;
24f4ad95
JS
250}
251
d980b3e1 252wxVariant wxAutomationObject::CallMethod(const wxString& member,
0a0e6a5b
WS
253 const wxVariant& arg1, const wxVariant& arg2,
254 const wxVariant& arg3, const wxVariant& arg4,
255 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 256{
0a0e6a5b
WS
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;
d980b3e1
JS
296}
297
298// Get/Set property
24f4ad95
JS
299wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const
300{
0a0e6a5b
WS
301 wxVariant retVariant;
302 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
303 {
304 retVariant.MakeNull();
305 }
306 return retVariant;
24f4ad95 307}
d980b3e1
JS
308wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const
309{
0a0e6a5b
WS
310 wxVariant retVariant;
311 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
312 {
313 retVariant.MakeNull();
314 }
315 return retVariant;
d980b3e1
JS
316}
317
318wxVariant wxAutomationObject::GetProperty(const wxString& property,
0a0e6a5b
WS
319 const wxVariant& arg1, const wxVariant& arg2,
320 const wxVariant& arg3, const wxVariant& arg4,
321 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 322{
0a0e6a5b
WS
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;
d980b3e1
JS
362}
363
364bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[])
365{
0a0e6a5b
WS
366 wxVariant retVariant;
367 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args))
368 {
369 return false;
370 }
371 return true;
d980b3e1
JS
372}
373
24f4ad95
JS
374bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args)
375{
0a0e6a5b
WS
376 wxVariant retVariant;
377 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args))
378 {
379 return false;
380 }
381 return true;
24f4ad95
JS
382}
383
d980b3e1 384bool wxAutomationObject::PutProperty(const wxString& property,
0a0e6a5b
WS
385 const wxVariant& arg1, const wxVariant& arg2,
386 const wxVariant& arg3, const wxVariant& arg4,
387 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 388{
0a0e6a5b
WS
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;
d980b3e1
JS
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.
432WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, wxVariant args[]) const
433{
0a0e6a5b
WS
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;
d980b3e1
JS
444}
445
24f4ad95
JS
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.
450WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, const wxVariant **args) const
451{
0a0e6a5b
WS
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;
24f4ad95
JS
462}
463
464
d980b3e1
JS
465// A way of initialising another wxAutomationObject with a dispatch object
466bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, wxVariant args[]) const
467{
0a0e6a5b
WS
468 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
469 if (dispatch)
470 {
471 obj.SetDispatchPtr(dispatch);
472 return true;
473 }
474 else
475 return false;
d980b3e1
JS
476}
477
24f4ad95
JS
478// A way of initialising another wxAutomationObject with a dispatch object
479bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, const wxVariant **args) const
480{
0a0e6a5b
WS
481 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
482 if (dispatch)
483 {
484 obj.SetDispatchPtr(dispatch);
485 return true;
486 }
487 else
488 return false;
24f4ad95
JS
489}
490
d980b3e1
JS
491// Get a dispatch pointer from the current object associated
492// with a class id
493bool wxAutomationObject::GetInstance(const wxString& classId) const
494{
0a0e6a5b
WS
495 if (m_dispatchPtr)
496 return false;
497
498 CLSID clsId;
499 IUnknown * pUnk = NULL;
500
5149f75b 501 wxBasicString unicodeName(classId);
0a0e6a5b
WS
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;
d980b3e1
JS
522}
523
524// Get a dispatch pointer from a new object associated
525// with the given class id
526bool wxAutomationObject::CreateInstance(const wxString& classId) const
527{
0a0e6a5b
WS
528 if (m_dispatchPtr)
529 return false;
530
531 CLSID clsId;
532
5149f75b 533 wxBasicString unicodeName(classId);
0a0e6a5b
WS
534
535 if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId)))
536 {
537 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
538 return false;
539 }
540
06936905
VZ
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)))
0a0e6a5b
WS
548 {
549 wxLogWarning(wxT("Cannot start an instance of this class."));
550 return false;
551 }
552
553 return true;
d980b3e1
JS
554}
555
556
e2898549 557WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
d980b3e1 558{
0a0e6a5b
WS
559 ClearVariant(&oleVariant);
560 if (variant.IsNull())
561 {
562 oleVariant.vt = VT_NULL;
563 return true;
564 }
d980b3e1
JS
565
566 wxString type(variant.GetType());
567
6b978929
JS
568
569 if (type == wxT("long"))
d980b3e1
JS
570 {
571 oleVariant.vt = VT_I4;
572 oleVariant.lVal = variant.GetLong() ;
573 }
6b978929
JS
574 // cVal not always present
575#ifndef __GNUWIN32__
576 else if (type == wxT("char"))
577 {
0a0e6a5b 578 oleVariant.vt=VT_I1; // Signed Char
6b978929
JS
579 oleVariant.cVal=variant.GetChar();
580 }
581#endif
223d09f6 582 else if (type == wxT("double"))
d980b3e1
JS
583 {
584 oleVariant.vt = VT_R8;
585 oleVariant.dblVal = variant.GetDouble();
586 }
223d09f6 587 else if (type == wxT("bool"))
d980b3e1
JS
588 {
589 oleVariant.vt = VT_BOOL;
7c5dc04f 590 // 'bool' required for VC++ 4 apparently
6b12494d 591#if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
7be1f0d9
JS
592 oleVariant.bool = variant.GetBool();
593#else
d980b3e1 594 oleVariant.boolVal = variant.GetBool();
7be1f0d9 595#endif
d980b3e1 596 }
223d09f6 597 else if (type == wxT("string"))
d980b3e1
JS
598 {
599 wxString str( variant.GetString() );
600 oleVariant.vt = VT_BSTR;
ed5317e5 601 oleVariant.bstrVal = wxConvertStringToOle(str);
d980b3e1 602 }
61bfe4b0
JS
603#if wxUSE_DATETIME
604 else if (type == wxT("datetime"))
605 {
606 wxDateTime date( variant.GetDateTime() );
607 oleVariant.vt = VT_DATE;
7520f3da 608
94113cc5 609 long dosDateTime = date.GetAsDOS();
11f104e5
WS
610 short dosDate = short((dosDateTime & 0xFFFF0000) >> 16);
611 short dosTime = short(dosDateTime & 0xFFFF);
7520f3da 612
94113cc5 613 DosDateTimeToVariantTime(dosDate, dosTime, & oleVariant.date);
61bfe4b0 614 }
457e6c54 615#endif
223d09f6 616 else if (type == wxT("void*"))
d980b3e1
JS
617 {
618 oleVariant.vt = VT_DISPATCH;
619 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
620 }
223d09f6 621 else if (type == wxT("list") || type == wxT("stringlist"))
d980b3e1
JS
622 {
623 oleVariant.vt = VT_VARIANT | VT_ARRAY;
624
0a0e6a5b
WS
625 SAFEARRAY *psa;
626 SAFEARRAYBOUND saBound;
627 VARIANTARG *pvargBase;
628 VARIANTARG *pvarg;
629 int i, j;
d980b3e1
JS
630
631 int iCount = variant.GetCount();
0a0e6a5b
WS
632
633 saBound.lLbound = 0;
634 saBound.cElements = iCount;
635
636 psa = SafeArrayCreate(VT_VARIANT, 1, &saBound);
637 if (psa == NULL)
638 return false;
639
640 SafeArrayAccessData(psa, (void**)&pvargBase);
641
642 pvarg = pvargBase;
643 for (i = 0; i < iCount; i++)
644 {
645 // copy each string in the list of strings
d980b3e1 646 wxVariant eachVariant(variant[i]);
ed5317e5 647 if (!wxConvertVariantToOle(eachVariant, * pvarg))
d980b3e1 648 {
0a0e6a5b
WS
649 // memory failure: back out and free strings alloc'ed up to
650 // now, and then the array itself.
651 pvarg = pvargBase;
652 for (j = 0; j < i; j++)
653 {
654 SysFreeString(pvarg->bstrVal);
655 pvarg++;
656 }
657 SafeArrayDestroy(psa);
658 return false;
659 }
660 pvarg++;
661 }
662
663 SafeArrayUnaccessData(psa);
d980b3e1
JS
664
665 oleVariant.parray = psa;
666 }
667 else
668 {
669 oleVariant.vt = VT_NULL;
0a0e6a5b 670 return false;
d980b3e1 671 }
0a0e6a5b 672 return true;
d980b3e1
JS
673}
674
675#ifndef VT_TYPEMASK
676#define VT_TYPEMASK 0xfff
677#endif
678
242019ee
VZ
679WXDLLEXPORT bool
680wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
d980b3e1 681{
e54266ad 682 bool ok = true;
242019ee 683 if ( oleVariant.vt & VT_ARRAY )
0a0e6a5b 684 {
242019ee
VZ
685
686 // Compute the total number of elements in all array dimensions
687 int cElements = 1;
688 for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ )
689 cElements *= oleVariant.parray->rgsabound[cDims].cElements;
690
691 // Get a pointer to the data
87fe783d
VZ
692 void* pvdata;
693 HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata);
242019ee
VZ
694 if ( FAILED(hr) )
695 return false;
696
87fe783d 697 switch (oleVariant.vt & VT_TYPEMASK)
0a0e6a5b 698 {
87fe783d
VZ
699 case VT_VARIANT:
700 {
701 variant.ClearList();
702 VARIANTARG *variant_data=(VARIANTARG*)pvdata;
703 for ( int i = 0; i < cElements; i++ )
704 {
705 VARIANTARG& oleElement = variant_data[i];
706 wxVariant vElement;
707 if ( !wxConvertOleToVariant(oleElement, vElement) )
708 {
709 ok = false;
710 variant.ClearList();
711 break;
712 }
713
714 variant.Append(vElement);
715 }
716 }
242019ee 717 break;
242019ee 718
87fe783d
VZ
719 case VT_BSTR:
720 {
721 wxArrayString strings;
722 BSTR *string_val=(BSTR*)pvdata;
723 for ( int i = 0; i < cElements; ++i )
724 {
725 wxString str=wxConvertStringFromOle(*string_val);
726 strings.Add(str);
727 ++string_val;
728 }
729 variant=strings;
730 }
731 break;
732
733 default:
734 wxLogDebug(_T("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
735 oleVariant.vt & VT_TYPEMASK);
736 variant = wxVariant();
737 ok = false;
738 break;
0a0e6a5b 739 }
242019ee
VZ
740
741 SafeArrayUnaccessData(oleVariant.parray);
742 }
743 else if ( oleVariant.vt & VT_BYREF )
744 {
745 switch ( oleVariant.vt & VT_TYPEMASK )
0a0e6a5b 746 {
242019ee
VZ
747 case VT_VARIANT:
748 {
749 VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref);
750 if (!wxConvertOleToVariant(oleReference,variant))
751 return false;
752 break;
753 }
754
755 default:
87fe783d
VZ
756 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),
757 oleVariant.vt);
242019ee 758 return false;
0a0e6a5b 759 }
242019ee
VZ
760 }
761 else // simply type (not array or reference)
762 {
87fe783d 763 switch ( oleVariant.vt & VT_TYPEMASK )
0a0e6a5b 764 {
242019ee
VZ
765 case VT_BSTR:
766 {
767 wxString str(wxConvertStringFromOle(oleVariant.bstrVal));
768 variant = str;
242019ee 769 }
87fe783d
VZ
770 break;
771
242019ee 772 case VT_DATE:
242019ee 773#if wxUSE_DATETIME
87fe783d 774 {
242019ee
VZ
775 unsigned short dosDate = 0;
776 unsigned short dosTime = 0;
777 VariantTimeToDosDateTime(oleVariant.date, & dosDate, & dosTime);
778
779 long dosDateTime = (dosDate << 16) | dosTime;
780 wxDateTime date;
781 date.SetFromDOS(dosDateTime);
782 variant = date;
242019ee 783 }
87fe783d
VZ
784#endif // wxUSE_DATETIME
785 break;
786
242019ee 787 case VT_I4:
87fe783d
VZ
788 variant = (long) oleVariant.lVal;
789 break;
790
242019ee 791 case VT_I2:
87fe783d
VZ
792 variant = (long) oleVariant.iVal;
793 break;
0a0e6a5b 794
242019ee 795 case VT_BOOL:
87fe783d
VZ
796 variant = oleVariant.boolVal != 0;
797 break;
798
242019ee 799 case VT_R8:
87fe783d
VZ
800 variant = oleVariant.dblVal;
801 break;
802
242019ee 803 case VT_DISPATCH:
87fe783d
VZ
804 variant = (void*) oleVariant.pdispVal;
805 break;
806
242019ee 807 case VT_NULL:
87fe783d
VZ
808 variant.MakeNull();
809 break;
810
242019ee 811 case VT_EMPTY:
87fe783d
VZ
812 break; // Ignore Empty Variant, used only during destruction of objects
813
242019ee 814 default:
87fe783d
VZ
815 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),
816 oleVariant.vt,oleVariant.vt&VT_TYPEMASK);
817 return false;
0a0e6a5b
WS
818 }
819 }
242019ee 820
e54266ad 821 return ok;
d980b3e1
JS
822}
823
d980b3e1
JS
824/*
825 * ClearVariant
826 *
827 * Zeros a variant structure without regard to current contents
828 */
829static void ClearVariant(VARIANTARG *pvarg)
830{
0a0e6a5b
WS
831 pvarg->vt = VT_EMPTY;
832 pvarg->wReserved1 = 0;
833 pvarg->wReserved2 = 0;
834 pvarg->wReserved3 = 0;
835 pvarg->lVal = 0;
d980b3e1
JS
836}
837
838/*
839 * ReleaseVariant
840 *
841 * Clears a particular variant structure and releases any external objects
842 * or memory contained in the variant. Supports the data types listed above.
843 */
844static void ReleaseVariant(VARIANTARG *pvarg)
845{
0a0e6a5b
WS
846 VARTYPE vt;
847 VARIANTARG _huge *pvargArray;
56fb1bca 848 LONG lLBound, lUBound, l;
0a0e6a5b 849
5c519b6c 850 vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags
0a0e6a5b
WS
851
852 // check if an array. If so, free its contents, then the array itself.
853 if (V_ISARRAY(pvarg))
854 {
855 // variant arrays are all this routine currently knows about. Since a
856 // variant can contain anything (even other arrays), call ourselves
857 // recursively.
858 if (vt == VT_VARIANT)
859 {
860 SafeArrayGetLBound(pvarg->parray, 1, &lLBound);
861 SafeArrayGetUBound(pvarg->parray, 1, &lUBound);
862
863 if (lUBound > lLBound)
864 {
865 lUBound -= lLBound;
866
867 SafeArrayAccessData(pvarg->parray, (void**)&pvargArray);
868
869 for (l = 0; l < lUBound; l++)
870 {
871 ReleaseVariant(pvargArray);
872 pvargArray++;
873 }
874
875 SafeArrayUnaccessData(pvarg->parray);
876 }
877 }
878 else
879 {
880 wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type"));
881 }
882
883 // Free the array itself.
884 SafeArrayDestroy(pvarg->parray);
885 }
886 else
887 {
888 switch (vt)
889 {
890 case VT_DISPATCH:
891 if (pvarg->pdispVal)
892 pvarg->pdispVal->Release();
893 break;
894
895 case VT_BSTR:
896 SysFreeString(pvarg->bstrVal);
897 break;
898
899 case VT_I2:
0a0e6932 900 case VT_I4:
0a0e6a5b
WS
901 case VT_BOOL:
902 case VT_R8:
903 case VT_ERROR: // to avoid erroring on an error return from Excel
0a0e6932 904 case VT_EMPTY:
b0fa01cc 905 case VT_DATE:
0a0e6a5b
WS
906 // no work for these types
907 break;
908
909 default:
910 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
911 break;
912 }
913 }
914
915 ClearVariant(pvarg);
d980b3e1
JS
916}
917
918#if 0
919
920void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr)
921{
0a0e6a5b
WS
922 TCHAR szBuf[512];
923
924 switch (GetScode(hr))
925 {
926 case DISP_E_UNKNOWNNAME:
927 wsprintf(szBuf, L"%s: Unknown name or named argument.", szMember);
928 break;
929
930 case DISP_E_BADPARAMCOUNT:
931 wsprintf(szBuf, L"%s: Incorrect number of arguments.", szMember);
932 break;
933
934 case DISP_E_EXCEPTION:
935 wsprintf(szBuf, L"%s: Error %d: ", szMember, pexcep->wCode);
936 if (pexcep->bstrDescription != NULL)
937 lstrcat(szBuf, pexcep->bstrDescription);
938 else
939 lstrcat(szBuf, L"<<No Description>>");
940 break;
941
942 case DISP_E_MEMBERNOTFOUND:
943 wsprintf(szBuf, L"%s: method or property not found.", szMember);
944 break;
945
946 case DISP_E_OVERFLOW:
947 wsprintf(szBuf, L"%s: Overflow while coercing argument values.", szMember);
948 break;
949
950 case DISP_E_NONAMEDARGS:
951 wsprintf(szBuf, L"%s: Object implementation does not support named arguments.",
952 szMember);
953 break;
954
955 case DISP_E_UNKNOWNLCID:
956 wsprintf(szBuf, L"%s: The locale ID is unknown.", szMember);
957 break;
958
959 case DISP_E_PARAMNOTOPTIONAL:
960 wsprintf(szBuf, L"%s: Missing a required parameter.", szMember);
961 break;
962
963 case DISP_E_PARAMNOTFOUND:
964 wsprintf(szBuf, L"%s: Argument not found, argument %d.", szMember, uiArgErr);
965 break;
966
967 case DISP_E_TYPEMISMATCH:
968 wsprintf(szBuf, L"%s: Type mismatch, argument %d.", szMember, uiArgErr);
969 break;
970
971 default:
3103e8a9 972 wsprintf(szBuf, L"%s: Unknown error occurred.", szMember);
0a0e6a5b
WS
973 break;
974 }
975
976 wxLogWarning(szBuf);
d980b3e1
JS
977}
978
979#endif
980
ca5c6ac3 981#endif // wxUSE_OLE_AUTOMATION