]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/automtn.cpp
changed wxWindow::Refresh() to refresh the window children as well (as wxGTK already...
[wxWidgets.git] / src / msw / ole / automtn.cpp
CommitLineData
d980b3e1
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: 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
65571936 9// Licence: wxWindows licence
d980b3e1
JS
10/////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
d980b3e1
JS
13#pragma implementation "automtn.h"
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#if defined(__BORLANDC__)
20#pragma hdrstop
21#endif
22
f6bcfd97 23#include "wx/defs.h"
d980b3e1 24
457e6c54 25// Watcom C++ gives a linker error if this is compiled in.
f6bcfd97 26// With Borland C++, all samples crash if this is compiled in.
6b12494d 27#if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
457e6c54 28
5283098e 29#define _FORCENAMELESSUNION
f6bcfd97 30#include "wx/log.h"
4676948b 31#include "wx/msw/private.h"
ed5317e5 32#include "wx/msw/ole/oleutils.h"
42e69d6b 33#include "wx/msw/ole/automtn.h"
b713f891 34#include "wx/math.h"
4676948b
JS
35
36#ifdef __WXWINCE__
37#include "wx/msw/wince/time.h"
38#else
f6bcfd97 39#include <time.h>
4676948b 40#endif
f6bcfd97 41
7dee726c
RS
42#include <wtypes.h>
43#include <unknwn.h>
4676948b 44
7dee726c
RS
45#include <ole2.h>
46#define _huge
4676948b
JS
47
48#ifndef __WXWINCE__
42e69d6b 49#include <ole2ver.h>
4676948b
JS
50#endif
51
42e69d6b 52#include <oleauto.h>
17b74d79 53
d980b3e1
JS
54// Verifies will fail if the needed buffer size is too large
55#define MAX_TIME_BUFFER_SIZE 128 // matches that in timecore.cpp
56#define MIN_DATE (-657434L) // about year 100
57#define MAX_DATE 2958465L // about year 9999
58
59// Half a second, expressed in days
60#define HALF_SECOND (1.0/172800.0)
61
62// One-based array of days in year at month start
63static int rgMonthDays[13] =
0a0e6a5b 64 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
d980b3e1 65
61bfe4b0
JS
66#if wxUSE_DATETIME
67#include "wx/datetime.h"
68
d980b3e1 69static BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
0a0e6a5b 70 WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest);
d980b3e1 71static BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest);
e421922f 72#endif // wxUSE_TIMEDATE
d980b3e1
JS
73
74static void ClearVariant(VARIANTARG *pvarg) ;
75static void ReleaseVariant(VARIANTARG *pvarg) ;
76// static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
77
78/*
79 * wxAutomationObject
80 */
81
82wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr)
83{
0a0e6a5b 84 m_dispatchPtr = dispatchPtr;
d980b3e1
JS
85}
86
87wxAutomationObject::~wxAutomationObject()
88{
0a0e6a5b
WS
89 if (m_dispatchPtr)
90 {
91 ((IDispatch*)m_dispatchPtr)->Release();
92 m_dispatchPtr = NULL;
93 }
d980b3e1
JS
94}
95
96#define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
97
98// For Put/Get, no named arguments are allowed.
99bool wxAutomationObject::Invoke(const wxString& member, int action,
100 wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const
101{
0a0e6a5b
WS
102 if (!m_dispatchPtr)
103 return false;
104
105 // nonConstMember is necessary because the wxString class doesn't have enough consts...
106 wxString nonConstMember(member);
107
108 int ch = nonConstMember.Find('.');
109 if (ch != -1)
110 {
111 // Use dot notation to get the next object
112 wxString member2(nonConstMember.Left((size_t) ch));
113 wxString rest(nonConstMember.Right(nonConstMember.Length() - ch - 1));
114 wxAutomationObject obj;
115 if (!GetObject(obj, member2))
116 return false;
117 return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs);
118 }
119
120 VARIANTARG vReturn;
121 ClearVariant(& vReturn);
122
123 VARIANTARG* vReturnPtr = & vReturn;
124
125 // Find number of names args
126 int namedArgCount = 0;
127 int i;
128 for (i = 0; i < noArgs; i++)
129 if (!INVOKEARG(i).GetName().IsNull())
12335fa6 130 {
0a0e6a5b
WS
131 namedArgCount ++;
132 }
133
134 int namedArgStringCount = namedArgCount + 1;
135 BSTR* argNames = new BSTR[namedArgStringCount];
136 argNames[0] = wxConvertStringToOle(member);
137
138 // Note that arguments are specified in reverse order
139 // (all totally logical; hey, we're dealing with OLE here.)
140
141 int j = 0;
142 for (i = 0; i < namedArgCount; i++)
143 {
144 if (!INVOKEARG(i).GetName().IsNull())
145 {
146 argNames[(namedArgCount-j)] = wxConvertStringToOle(INVOKEARG(i).GetName());
147 j ++;
148 }
149 }
150
151 // + 1 for the member name, + 1 again in case we're a 'put'
152 DISPID* dispIds = new DISPID[namedArgCount + 2];
153
154 HRESULT hr;
155 DISPPARAMS dispparams;
156 unsigned int uiArgErr;
157 EXCEPINFO excep;
158
159 // Get the IDs for the member and its arguments. GetIDsOfNames expects the
160 // member name as the first name, followed by argument names (if any).
161 hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, argNames,
162 1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, dispIds);
163 if (FAILED(hr))
164 {
165// ShowException(szMember, hr, NULL, 0);
166 delete[] argNames;
167 delete[] dispIds;
168 return false;
169 }
170
171 // if doing a property put(ref), we need to adjust the first argument to have a
172 // named arg of DISPID_PROPERTYPUT.
173 if (action & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
174 {
175 namedArgCount = 1;
176 dispIds[1] = DISPID_PROPERTYPUT;
177 vReturnPtr = (VARIANTARG*) NULL;
178 }
179
180 // Convert the wxVariants to VARIANTARGs
181 VARIANTARG* oleArgs = new VARIANTARG[noArgs];
182 for (i = 0; i < noArgs; i++)
183 {
184 // Again, reverse args
185 if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i]))
186 {
187 delete[] argNames;
188 delete[] dispIds;
12335fa6 189 delete[] oleArgs;
0a0e6a5b
WS
190 return false;
191 }
192 }
193
194 dispparams.rgdispidNamedArgs = dispIds + 1;
195 dispparams.rgvarg = oleArgs;
196 dispparams.cArgs = noArgs;
197 dispparams.cNamedArgs = namedArgCount;
198
199 excep.pfnDeferredFillIn = NULL;
200
201 hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT,
5c519b6c 202 (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
0a0e6a5b
WS
203
204 for (i = 0; i < namedArgStringCount; i++)
205 {
206 SysFreeString(argNames[i]);
207 }
208 delete[] argNames;
209 delete[] dispIds;
210
211 for (i = 0; i < noArgs; i++)
212 ReleaseVariant(& oleArgs[i]) ;
213 delete[] oleArgs;
214
215 if (FAILED(hr))
216 {
217 // display the exception information if appropriate:
218// ShowException((const char*) member, hr, &excep, uiArgErr);
219
220 // free exception structure information
221 SysFreeString(excep.bstrSource);
222 SysFreeString(excep.bstrDescription);
223 SysFreeString(excep.bstrHelpFile);
224
225 if (vReturnPtr)
226 ReleaseVariant(vReturnPtr);
227 return false;
228 }
229 else
230 {
231 if (vReturnPtr)
232 {
233 // Convert result to wxVariant form
234 wxConvertOleToVariant(vReturn, retValue);
235 // Mustn't release the dispatch pointer
236 if (vReturn.vt == VT_DISPATCH)
237 {
238 vReturn.pdispVal = (IDispatch*) NULL;
239 }
240 ReleaseVariant(& vReturn);
12335fa6 241 }
0a0e6a5b
WS
242 }
243 return true;
d980b3e1
JS
244}
245
246// Invoke a member function
247wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[])
248{
0a0e6a5b
WS
249 wxVariant retVariant;
250 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args))
251 {
252 retVariant.MakeNull();
253 }
254 return retVariant;
d980b3e1
JS
255}
256
24f4ad95
JS
257wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args)
258{
0a0e6a5b
WS
259 wxVariant retVariant;
260 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args))
261 {
262 retVariant.MakeNull();
263 }
264 return retVariant;
24f4ad95
JS
265}
266
d980b3e1 267wxVariant wxAutomationObject::CallMethod(const wxString& member,
0a0e6a5b
WS
268 const wxVariant& arg1, const wxVariant& arg2,
269 const wxVariant& arg3, const wxVariant& arg4,
270 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 271{
0a0e6a5b
WS
272 const wxVariant** args = new const wxVariant*[6];
273 int i = 0;
274 if (!arg1.IsNull())
275 {
276 args[i] = & arg1;
277 i ++;
278 }
279 if (!arg2.IsNull())
280 {
281 args[i] = & arg2;
282 i ++;
283 }
284 if (!arg3.IsNull())
285 {
286 args[i] = & arg3;
287 i ++;
288 }
289 if (!arg4.IsNull())
290 {
291 args[i] = & arg4;
292 i ++;
293 }
294 if (!arg5.IsNull())
295 {
296 args[i] = & arg5;
297 i ++;
298 }
299 if (!arg6.IsNull())
300 {
301 args[i] = & arg6;
302 i ++;
303 }
304 wxVariant retVariant;
305 if (!Invoke(member, DISPATCH_METHOD, retVariant, i, NULL, args))
306 {
307 retVariant.MakeNull();
308 }
309 delete[] args;
310 return retVariant;
d980b3e1
JS
311}
312
313// Get/Set property
24f4ad95
JS
314wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const
315{
0a0e6a5b
WS
316 wxVariant retVariant;
317 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
318 {
319 retVariant.MakeNull();
320 }
321 return retVariant;
24f4ad95 322}
d980b3e1
JS
323wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const
324{
0a0e6a5b
WS
325 wxVariant retVariant;
326 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
327 {
328 retVariant.MakeNull();
329 }
330 return retVariant;
d980b3e1
JS
331}
332
333wxVariant wxAutomationObject::GetProperty(const wxString& property,
0a0e6a5b
WS
334 const wxVariant& arg1, const wxVariant& arg2,
335 const wxVariant& arg3, const wxVariant& arg4,
336 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 337{
0a0e6a5b
WS
338 const wxVariant** args = new const wxVariant*[6];
339 int i = 0;
340 if (!arg1.IsNull())
341 {
342 args[i] = & arg1;
343 i ++;
344 }
345 if (!arg2.IsNull())
346 {
347 args[i] = & arg2;
348 i ++;
349 }
350 if (!arg3.IsNull())
351 {
352 args[i] = & arg3;
353 i ++;
354 }
355 if (!arg4.IsNull())
356 {
357 args[i] = & arg4;
358 i ++;
359 }
360 if (!arg5.IsNull())
361 {
362 args[i] = & arg5;
363 i ++;
364 }
365 if (!arg6.IsNull())
366 {
367 args[i] = & arg6;
368 i ++;
369 }
370 wxVariant retVariant;
371 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, i, NULL, args))
372 {
373 retVariant.MakeNull();
374 }
375 delete[] args;
376 return retVariant;
d980b3e1
JS
377}
378
379bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[])
380{
0a0e6a5b
WS
381 wxVariant retVariant;
382 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args))
383 {
384 return false;
385 }
386 return true;
d980b3e1
JS
387}
388
24f4ad95
JS
389bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args)
390{
0a0e6a5b
WS
391 wxVariant retVariant;
392 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args))
393 {
394 return false;
395 }
396 return true;
24f4ad95
JS
397}
398
d980b3e1 399bool wxAutomationObject::PutProperty(const wxString& property,
0a0e6a5b
WS
400 const wxVariant& arg1, const wxVariant& arg2,
401 const wxVariant& arg3, const wxVariant& arg4,
402 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 403{
0a0e6a5b
WS
404 const wxVariant** args = new const wxVariant*[6];
405 int i = 0;
406 if (!arg1.IsNull())
407 {
408 args[i] = & arg1;
409 i ++;
410 }
411 if (!arg2.IsNull())
412 {
413 args[i] = & arg2;
414 i ++;
415 }
416 if (!arg3.IsNull())
417 {
418 args[i] = & arg3;
419 i ++;
420 }
421 if (!arg4.IsNull())
422 {
423 args[i] = & arg4;
424 i ++;
425 }
426 if (!arg5.IsNull())
427 {
428 args[i] = & arg5;
429 i ++;
430 }
431 if (!arg6.IsNull())
432 {
433 args[i] = & arg6;
434 i ++;
435 }
436 wxVariant retVariant;
437 bool ret = Invoke(property, DISPATCH_PROPERTYPUT, retVariant, i, NULL, args);
438 delete[] args;
439 return ret;
d980b3e1
JS
440}
441
442
443// Uses DISPATCH_PROPERTYGET
444// and returns a dispatch pointer. The calling code should call Release
445// on the pointer, though this could be implicit by constructing an wxAutomationObject
446// with it and letting the destructor call Release.
447WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, wxVariant args[]) const
448{
0a0e6a5b
WS
449 wxVariant retVariant;
450 if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
451 {
452 if (retVariant.GetType() == wxT("void*"))
453 {
454 return (WXIDISPATCH*) retVariant.GetVoidPtr();
455 }
456 }
457
458 return (WXIDISPATCH*) NULL;
d980b3e1
JS
459}
460
24f4ad95
JS
461// Uses DISPATCH_PROPERTYGET
462// and returns a dispatch pointer. The calling code should call Release
463// on the pointer, though this could be implicit by constructing an wxAutomationObject
464// with it and letting the destructor call Release.
465WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, const wxVariant **args) const
466{
0a0e6a5b
WS
467 wxVariant retVariant;
468 if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
469 {
470 if (retVariant.GetType() == wxT("void*"))
471 {
472 return (WXIDISPATCH*) retVariant.GetVoidPtr();
473 }
474 }
475
476 return (WXIDISPATCH*) NULL;
24f4ad95
JS
477}
478
479
d980b3e1
JS
480// A way of initialising another wxAutomationObject with a dispatch object
481bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, wxVariant args[]) const
482{
0a0e6a5b
WS
483 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
484 if (dispatch)
485 {
486 obj.SetDispatchPtr(dispatch);
487 return true;
488 }
489 else
490 return false;
d980b3e1
JS
491}
492
24f4ad95
JS
493// A way of initialising another wxAutomationObject with a dispatch object
494bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, const wxVariant **args) const
495{
0a0e6a5b
WS
496 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
497 if (dispatch)
498 {
499 obj.SetDispatchPtr(dispatch);
500 return true;
501 }
502 else
503 return false;
24f4ad95
JS
504}
505
d980b3e1
JS
506// Get a dispatch pointer from the current object associated
507// with a class id
508bool wxAutomationObject::GetInstance(const wxString& classId) const
509{
0a0e6a5b
WS
510 if (m_dispatchPtr)
511 return false;
512
513 CLSID clsId;
514 IUnknown * pUnk = NULL;
515
516 wxBasicString unicodeName(classId.mb_str());
517
518 if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId)))
519 {
520 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
521 return false;
522 }
523
524 if (FAILED(GetActiveObject(clsId, NULL, &pUnk)))
525 {
526 wxLogWarning(wxT("Cannot find an active object"));
527 return false;
528 }
529
530 if (pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr) != S_OK)
531 {
532 wxLogWarning(wxT("Cannot find IDispatch interface"));
533 return false;
534 }
535
536 return true;
d980b3e1
JS
537}
538
539// Get a dispatch pointer from a new object associated
540// with the given class id
541bool wxAutomationObject::CreateInstance(const wxString& classId) const
542{
0a0e6a5b
WS
543 if (m_dispatchPtr)
544 return false;
545
546 CLSID clsId;
547
548 wxBasicString unicodeName(classId.mb_str());
549
550 if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId)))
551 {
552 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
553 return false;
554 }
555
556 // start a new copy of Excel, grab the IDispatch interface
557 if (FAILED(CoCreateInstance(clsId, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&m_dispatchPtr)))
558 {
559 wxLogWarning(wxT("Cannot start an instance of this class."));
560 return false;
561 }
562
563 return true;
d980b3e1
JS
564}
565
566
ed5317e5 567bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
d980b3e1 568{
0a0e6a5b
WS
569 ClearVariant(&oleVariant);
570 if (variant.IsNull())
571 {
572 oleVariant.vt = VT_NULL;
573 return true;
574 }
d980b3e1
JS
575
576 wxString type(variant.GetType());
577
6b978929
JS
578
579 if (type == wxT("long"))
d980b3e1
JS
580 {
581 oleVariant.vt = VT_I4;
582 oleVariant.lVal = variant.GetLong() ;
583 }
6b978929
JS
584 // cVal not always present
585#ifndef __GNUWIN32__
586 else if (type == wxT("char"))
587 {
0a0e6a5b 588 oleVariant.vt=VT_I1; // Signed Char
6b978929
JS
589 oleVariant.cVal=variant.GetChar();
590 }
591#endif
223d09f6 592 else if (type == wxT("double"))
d980b3e1
JS
593 {
594 oleVariant.vt = VT_R8;
595 oleVariant.dblVal = variant.GetDouble();
596 }
223d09f6 597 else if (type == wxT("bool"))
d980b3e1
JS
598 {
599 oleVariant.vt = VT_BOOL;
7c5dc04f 600 // 'bool' required for VC++ 4 apparently
6b12494d 601#if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
7be1f0d9
JS
602 oleVariant.bool = variant.GetBool();
603#else
d980b3e1 604 oleVariant.boolVal = variant.GetBool();
7be1f0d9 605#endif
d980b3e1 606 }
223d09f6 607 else if (type == wxT("string"))
d980b3e1
JS
608 {
609 wxString str( variant.GetString() );
610 oleVariant.vt = VT_BSTR;
ed5317e5 611 oleVariant.bstrVal = wxConvertStringToOle(str);
d980b3e1 612 }
61bfe4b0
JS
613#if wxUSE_DATETIME
614 else if (type == wxT("datetime"))
615 {
616 wxDateTime date( variant.GetDateTime() );
617 oleVariant.vt = VT_DATE;
618
5c519b6c 619 if (!OleDateFromTm((WORD)date.GetYear(), date.GetMonth(), date.GetDay(),
0a0e6a5b
WS
620 date.GetHour(), date.GetMinute(), date.GetSecond(), oleVariant.date))
621 return false;
61bfe4b0 622 }
457e6c54 623#endif
223d09f6 624 else if (type == wxT("void*"))
d980b3e1
JS
625 {
626 oleVariant.vt = VT_DISPATCH;
627 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
628 }
223d09f6 629 else if (type == wxT("list") || type == wxT("stringlist"))
d980b3e1
JS
630 {
631 oleVariant.vt = VT_VARIANT | VT_ARRAY;
632
0a0e6a5b
WS
633 SAFEARRAY *psa;
634 SAFEARRAYBOUND saBound;
635 VARIANTARG *pvargBase;
636 VARIANTARG *pvarg;
637 int i, j;
d980b3e1
JS
638
639 int iCount = variant.GetCount();
0a0e6a5b
WS
640
641 saBound.lLbound = 0;
642 saBound.cElements = iCount;
643
644 psa = SafeArrayCreate(VT_VARIANT, 1, &saBound);
645 if (psa == NULL)
646 return false;
647
648 SafeArrayAccessData(psa, (void**)&pvargBase);
649
650 pvarg = pvargBase;
651 for (i = 0; i < iCount; i++)
652 {
653 // copy each string in the list of strings
d980b3e1 654 wxVariant eachVariant(variant[i]);
ed5317e5 655 if (!wxConvertVariantToOle(eachVariant, * pvarg))
d980b3e1 656 {
0a0e6a5b
WS
657 // memory failure: back out and free strings alloc'ed up to
658 // now, and then the array itself.
659 pvarg = pvargBase;
660 for (j = 0; j < i; j++)
661 {
662 SysFreeString(pvarg->bstrVal);
663 pvarg++;
664 }
665 SafeArrayDestroy(psa);
666 return false;
667 }
668 pvarg++;
669 }
670
671 SafeArrayUnaccessData(psa);
d980b3e1
JS
672
673 oleVariant.parray = psa;
674 }
675 else
676 {
677 oleVariant.vt = VT_NULL;
0a0e6a5b 678 return false;
d980b3e1 679 }
0a0e6a5b 680 return true;
d980b3e1
JS
681}
682
683#ifndef VT_TYPEMASK
684#define VT_TYPEMASK 0xfff
685#endif
686
ed5317e5 687bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
d980b3e1 688{
0a0e6a5b
WS
689 switch (oleVariant.vt & VT_TYPEMASK)
690 {
691 case VT_BSTR:
692 {
693 wxString str(wxConvertStringFromOle(oleVariant.bstrVal));
694 variant = str;
695 break;
696 }
697 case VT_DATE:
698 {
61bfe4b0 699#if wxUSE_DATETIME
f6bcfd97 700 struct tm tmTemp;
0a0e6a5b
WS
701 if (!TmFromOleDate(oleVariant.date, tmTemp))
702 return false;
d980b3e1 703
5c519b6c
WS
704 wxDateTime date((wxDateTime::wxDateTime_t) tmTemp.tm_yday,
705 (wxDateTime::Month) tmTemp.tm_mon,
706 tmTemp.tm_year,
707 (wxDateTime::wxDateTime_t) tmTemp.tm_hour,
708 (wxDateTime::wxDateTime_t) tmTemp.tm_min,
709 (wxDateTime::wxDateTime_t) tmTemp.tm_sec);
d980b3e1 710
0a0e6a5b 711 variant = date;
f6bcfd97
BP
712#endif
713
714 break;
0a0e6a5b
WS
715 }
716 case VT_I4:
717 {
718 variant = (long) oleVariant.lVal;
719 break;
720 }
721 case VT_I2:
722 {
723 variant = (long) oleVariant.iVal;
724 break;
725 }
726
727 case VT_BOOL:
728 {
6b12494d 729#if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC
25889d3c 730#ifndef HAVE_BOOL // Can't use bool operator if no native bool type
0a0e6a5b 731 variant = (long) (oleVariant.bool != 0);
25889d3c 732#else
0a0e6a5b 733 variant = (bool) (oleVariant.bool != 0);
25889d3c 734#endif
f6bcfd97
BP
735#else
736#ifndef HAVE_BOOL // Can't use bool operator if no native bool type
0a0e6a5b 737 variant = (long) (oleVariant.boolVal != 0);
7be1f0d9 738#else
0a0e6a5b 739 variant = (bool) (oleVariant.boolVal != 0);
f6bcfd97 740#endif
7be1f0d9 741#endif
0a0e6a5b
WS
742 break;
743 }
744 case VT_R8:
745 {
746 variant = oleVariant.dblVal;
747 break;
748 }
749 case VT_ARRAY:
750 {
751 variant.ClearList();
752
753 int cDims, cElements, i;
754 VARIANTARG* pvdata;
755
756 // Iterate the dimensions: number of elements is x*y*z
757 for (cDims = 0, cElements = 1;
758 cDims < oleVariant.parray->cDims; cDims ++)
759 cElements *= oleVariant.parray->rgsabound[cDims].cElements;
760
761 // Get a pointer to the data
762 HRESULT hr = SafeArrayAccessData(oleVariant.parray, (void HUGEP* FAR*) & pvdata);
763 if (hr != NOERROR)
764 return false;
765 // Iterate the data.
766 for (i = 0; i < cElements; i++)
767 {
768 VARIANTARG& oleElement = pvdata[i];
769 wxVariant vElement;
770 if (!wxConvertOleToVariant(oleElement, vElement))
771 return false;
772
773 variant.Append(vElement);
774 }
775 SafeArrayUnaccessData(oleVariant.parray);
776 break;
777 }
778 case VT_DISPATCH:
779 {
780 variant = (void*) oleVariant.pdispVal;
781 break;
782 }
783 case VT_NULL:
784 {
785 variant.MakeNull();
786 break;
787 }
788 case VT_EMPTY:
789 {
790 break; // Ignore Empty Variant, used only during destruction of objects
791 }
792 default:
793 {
794 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type"));
795 return false;
796 }
797 }
798 return true;
d980b3e1
JS
799}
800
ed5317e5 801BSTR wxConvertStringToOle(const wxString& str)
d980b3e1
JS
802{
803/*
0a0e6a5b
WS
804 unsigned int len = strlen((const char*) str);
805 unsigned short* s = new unsigned short[len*2+2];
806 unsigned int i;
807 memset(s, 0, len*2+2);
808 for (i=0; i < len; i++)
809 s[i*2] = str[i];
d980b3e1 810*/
0a0e6a5b
WS
811 wxBasicString bstr(str.mb_str());
812 return bstr.Get();
d980b3e1
JS
813}
814
ed5317e5 815wxString wxConvertStringFromOle(BSTR bStr)
d980b3e1 816{
2b5f62a0
VZ
817#if wxUSE_UNICODE
818 wxString str(bStr);
819#else
0a0e6a5b
WS
820 int len = SysStringLen(bStr) + 1;
821 char *buf = new char[len];
822 (void)wcstombs( buf, bStr, len);
823 wxString str(buf);
824 delete[] buf;
2b5f62a0 825#endif
0a0e6a5b 826 return str;
d980b3e1
JS
827}
828
829// ----------------------------------------------------------------------------
ed5317e5 830// wxBasicString
d980b3e1
JS
831// ----------------------------------------------------------------------------
832
833// ctor takes an ANSI string and transforms it to Unicode
ed5317e5
JS
834wxBasicString::wxBasicString(const char *sz)
835{
836 Init(sz);
837}
838
839// ctor takes an ANSI or Unicode string and transforms it to Unicode
840wxBasicString::wxBasicString(const wxString& str)
d980b3e1 841{
ed5317e5
JS
842#if wxUSE_UNICODE
843 m_wzBuf = new OLECHAR[str.Length() + 1];
844 memcpy(m_wzBuf, str.c_str(), str.Length()*2);
845 m_wzBuf[str.Length()] = L'\0';
846#else
847 Init(str.c_str());
848#endif
849}
850
851// Takes an ANSI string and transforms it to Unicode
852void wxBasicString::Init(const char *sz)
853{
854 // get the size of required buffer
855 UINT lenAnsi = strlen(sz);
856#ifdef __MWERKS__
857 UINT lenWide = lenAnsi * 2 ;
858#else
859 UINT lenWide = mbstowcs(NULL, sz, lenAnsi);
860#endif
0a0e6a5b 861
ed5317e5
JS
862 if ( lenWide > 0 ) {
863 m_wzBuf = new OLECHAR[lenWide + 1];
864 mbstowcs(m_wzBuf, sz, lenAnsi);
865 m_wzBuf[lenWide] = L'\0';
866 }
867 else {
868 m_wzBuf = NULL;
869 }
d980b3e1
JS
870}
871
872// dtor frees memory
ed5317e5 873wxBasicString::~wxBasicString()
d980b3e1
JS
874{
875 delete [] m_wzBuf;
876}
877
878/////////////////////////////////////////////////////////////////////////////
879// COleDateTime class HELPERS - implementation
880
881BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
0a0e6a5b 882 WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest)
d980b3e1 883{
0a0e6a5b
WS
884 // Validate year and month (ignore day of week and milliseconds)
885 if (wYear > 9999 || wMonth < 1 || wMonth > 12)
886 return FALSE;
d980b3e1 887
0a0e6a5b
WS
888 // Check for leap year and set the number of days in the month
889 BOOL bLeapYear = ((wYear & 3) == 0) &&
890 ((wYear % 100) != 0 || (wYear % 400) == 0);
d980b3e1 891
0a0e6a5b
WS
892 int nDaysInMonth =
893 rgMonthDays[wMonth] - rgMonthDays[wMonth-1] +
894 ((bLeapYear && wDay == 29 && wMonth == 2) ? 1 : 0);
d980b3e1 895
0a0e6a5b
WS
896 // Finish validating the date
897 if (wDay < 1 || wDay > nDaysInMonth ||
898 wHour > 23 || wMinute > 59 ||
899 wSecond > 59)
900 {
901 return FALSE;
902 }
d980b3e1 903
0a0e6a5b
WS
904 // Cache the date in days and time in fractional days
905 long nDate;
906 double dblTime;
d980b3e1 907
0a0e6a5b
WS
908 //It is a valid date; make Jan 1, 1AD be 1
909 nDate = wYear*365L + wYear/4 - wYear/100 + wYear/400 +
910 rgMonthDays[wMonth-1] + wDay;
d980b3e1 911
0a0e6a5b
WS
912 // If leap year and it's before March, subtract 1:
913 if (wMonth <= 2 && bLeapYear)
914 --nDate;
d980b3e1 915
0a0e6a5b
WS
916 // Offset so that 12/30/1899 is 0
917 nDate -= 693959L;
d980b3e1 918
0a0e6a5b
WS
919 dblTime = (((long)wHour * 3600L) + // hrs in seconds
920 ((long)wMinute * 60L) + // mins in seconds
921 ((long)wSecond)) / 86400.;
d980b3e1 922
0a0e6a5b 923 dtDest = (double) nDate + ((nDate >= 0) ? dblTime : -dblTime);
d980b3e1 924
0a0e6a5b 925 return TRUE;
d980b3e1
JS
926}
927
928BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest)
929{
0a0e6a5b
WS
930 // The legal range does not actually span year 0 to 9999.
931 if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
932 return FALSE;
933
934 long nDaysAbsolute; // Number of days since 1/1/0
935 long nSecsInDay; // Time in seconds since midnight
936 long nMinutesInDay; // Minutes in day
937
938 long n400Years; // Number of 400 year increments since 1/1/0
939 long n400Century; // Century within 400 year block (0,1,2 or 3)
940 long n4Years; // Number of 4 year increments since 1/1/0
941 long n4Day; // Day within 4 year block
942 // (0 is 1/1/yr1, 1460 is 12/31/yr4)
943 long n4Yr; // Year within 4 year block (0,1,2 or 3)
944 BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year
945
946 double dblDate = dtSrc; // tempory serial date
947
948 // Round to the second
949 dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);
950
951 nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899
952
953 dblDate = fabs(dblDate);
954 nSecsInDay = (long)((dblDate - floor(dblDate)) * 86400.);
955
956 // Calculate the day of week (sun=1, mon=2...)
957 // -1 because 1/1/0 is Sat. +1 because we want 1-based
958 tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1;
959
960 // Leap years every 4 yrs except centuries not multiples of 400.
961 n400Years = (long)(nDaysAbsolute / 146097L);
962
963 // Set nDaysAbsolute to day within 400-year block
964 nDaysAbsolute %= 146097L;
965
966 // -1 because first century has extra day
967 n400Century = (long)((nDaysAbsolute - 1) / 36524L);
968
969 // Non-leap century
970 if (n400Century != 0)
971 {
972 // Set nDaysAbsolute to day within century
973 nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;
974
975 // +1 because 1st 4 year increment has 1460 days
976 n4Years = (long)((nDaysAbsolute + 1) / 1461L);
977
978 if (n4Years != 0)
979 n4Day = (long)((nDaysAbsolute + 1) % 1461L);
980 else
981 {
982 bLeap4 = FALSE;
983 n4Day = (long)nDaysAbsolute;
984 }
985 }
986 else
987 {
988 // Leap century - not special case!
989 n4Years = (long)(nDaysAbsolute / 1461L);
990 n4Day = (long)(nDaysAbsolute % 1461L);
991 }
992
993 if (bLeap4)
994 {
995 // -1 because first year has 366 days
996 n4Yr = (n4Day - 1) / 365;
997
998 if (n4Yr != 0)
999 n4Day = (n4Day - 1) % 365;
1000 }
1001 else
1002 {
1003 n4Yr = n4Day / 365;
1004 n4Day %= 365;
1005 }
1006
1007 // n4Day is now 0-based day of year. Save 1-based day of year, year number
1008 tmDest.tm_yday = (int)n4Day + 1;
1009 tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;
1010
1011 // Handle leap year: before, on, and after Feb. 29.
1012 if (n4Yr == 0 && bLeap4)
1013 {
1014 // Leap Year
1015 if (n4Day == 59)
1016 {
1017 /* Feb. 29 */
1018 tmDest.tm_mon = 2;
1019 tmDest.tm_mday = 29;
1020 goto DoTime;
1021 }
1022
1023 // Pretend it's not a leap year for month/day comp.
1024 if (n4Day >= 60)
1025 --n4Day;
1026 }
1027
1028 // Make n4DaY a 1-based day of non-leap year and compute
1029 // month/day for everything but Feb. 29.
1030 ++n4Day;
1031
1032 // Month number always >= n/32, so save some loop time */
1033 for (tmDest.tm_mon = (n4Day >> 5) + 1;
1034 n4Day > rgMonthDays[tmDest.tm_mon]; tmDest.tm_mon++)
1035 ;
1036
1037 tmDest.tm_mday = (int)(n4Day - rgMonthDays[tmDest.tm_mon-1]);
d980b3e1
JS
1038
1039DoTime:
0a0e6a5b
WS
1040 if (nSecsInDay == 0)
1041 tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
1042 else
1043 {
1044 tmDest.tm_sec = (int)nSecsInDay % 60L;
1045 nMinutesInDay = nSecsInDay / 60L;
1046 tmDest.tm_min = (int)nMinutesInDay % 60;
1047 tmDest.tm_hour = (int)nMinutesInDay / 60;
1048 }
1049
1050 return TRUE;
d980b3e1
JS
1051}
1052
b21624e7
VZ
1053// this function is not used
1054#if 0
d980b3e1
JS
1055void TmConvertToStandardFormat(struct tm& tmSrc)
1056{
0a0e6a5b
WS
1057 // Convert afx internal tm to format expected by runtimes (_tcsftime, etc)
1058 tmSrc.tm_year -= 1900; // year is based on 1900
1059 tmSrc.tm_mon -= 1; // month of year is 0-based
1060 tmSrc.tm_wday -= 1; // day of week is 0-based
1061 tmSrc.tm_yday -= 1; // day of year is 0-based
d980b3e1
JS
1062}
1063
1064double DoubleFromDate(DATE dt)
1065{
0a0e6a5b
WS
1066 // No problem if positive
1067 if (dt >= 0)
1068 return dt;
1069
1070 // If negative, must convert since negative dates not continuous
1071 // (examples: -1.25 to -.75, -1.50 to -.50, -1.75 to -.25)
1072 double temp = ceil(dt);
1073 return temp - (dt - temp);
d980b3e1
JS
1074}
1075
1076DATE DateFromDouble(double dbl)
1077{
0a0e6a5b
WS
1078 // No problem if positive
1079 if (dbl >= 0)
1080 return dbl;
1081
1082 // If negative, must convert since negative dates not continuous
1083 // (examples: -.75 to -1.25, -.50 to -1.50, -.25 to -1.75)
1084 double temp = floor(dbl); // dbl is now whole part
1085 return temp + (temp - dbl);
d980b3e1 1086}
b21624e7 1087#endif // 0
d980b3e1
JS
1088
1089/*
1090 * ClearVariant
1091 *
1092 * Zeros a variant structure without regard to current contents
1093 */
1094static void ClearVariant(VARIANTARG *pvarg)
1095{
0a0e6a5b
WS
1096 pvarg->vt = VT_EMPTY;
1097 pvarg->wReserved1 = 0;
1098 pvarg->wReserved2 = 0;
1099 pvarg->wReserved3 = 0;
1100 pvarg->lVal = 0;
d980b3e1
JS
1101}
1102
1103/*
1104 * ReleaseVariant
1105 *
1106 * Clears a particular variant structure and releases any external objects
1107 * or memory contained in the variant. Supports the data types listed above.
1108 */
1109static void ReleaseVariant(VARIANTARG *pvarg)
1110{
0a0e6a5b
WS
1111 VARTYPE vt;
1112 VARIANTARG _huge *pvargArray;
1113 long lLBound, lUBound, l;
1114
5c519b6c 1115 vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags
0a0e6a5b
WS
1116
1117 // check if an array. If so, free its contents, then the array itself.
1118 if (V_ISARRAY(pvarg))
1119 {
1120 // variant arrays are all this routine currently knows about. Since a
1121 // variant can contain anything (even other arrays), call ourselves
1122 // recursively.
1123 if (vt == VT_VARIANT)
1124 {
1125 SafeArrayGetLBound(pvarg->parray, 1, &lLBound);
1126 SafeArrayGetUBound(pvarg->parray, 1, &lUBound);
1127
1128 if (lUBound > lLBound)
1129 {
1130 lUBound -= lLBound;
1131
1132 SafeArrayAccessData(pvarg->parray, (void**)&pvargArray);
1133
1134 for (l = 0; l < lUBound; l++)
1135 {
1136 ReleaseVariant(pvargArray);
1137 pvargArray++;
1138 }
1139
1140 SafeArrayUnaccessData(pvarg->parray);
1141 }
1142 }
1143 else
1144 {
1145 wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type"));
1146 }
1147
1148 // Free the array itself.
1149 SafeArrayDestroy(pvarg->parray);
1150 }
1151 else
1152 {
1153 switch (vt)
1154 {
1155 case VT_DISPATCH:
1156 if (pvarg->pdispVal)
1157 pvarg->pdispVal->Release();
1158 break;
1159
1160 case VT_BSTR:
1161 SysFreeString(pvarg->bstrVal);
1162 break;
1163
1164 case VT_I2:
1165 case VT_BOOL:
1166 case VT_R8:
1167 case VT_ERROR: // to avoid erroring on an error return from Excel
1168 // no work for these types
1169 break;
1170
1171 default:
1172 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
1173 break;
1174 }
1175 }
1176
1177 ClearVariant(pvarg);
d980b3e1
JS
1178}
1179
1180#if 0
1181
1182void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr)
1183{
0a0e6a5b
WS
1184 TCHAR szBuf[512];
1185
1186 switch (GetScode(hr))
1187 {
1188 case DISP_E_UNKNOWNNAME:
1189 wsprintf(szBuf, L"%s: Unknown name or named argument.", szMember);
1190 break;
1191
1192 case DISP_E_BADPARAMCOUNT:
1193 wsprintf(szBuf, L"%s: Incorrect number of arguments.", szMember);
1194 break;
1195
1196 case DISP_E_EXCEPTION:
1197 wsprintf(szBuf, L"%s: Error %d: ", szMember, pexcep->wCode);
1198 if (pexcep->bstrDescription != NULL)
1199 lstrcat(szBuf, pexcep->bstrDescription);
1200 else
1201 lstrcat(szBuf, L"<<No Description>>");
1202 break;
1203
1204 case DISP_E_MEMBERNOTFOUND:
1205 wsprintf(szBuf, L"%s: method or property not found.", szMember);
1206 break;
1207
1208 case DISP_E_OVERFLOW:
1209 wsprintf(szBuf, L"%s: Overflow while coercing argument values.", szMember);
1210 break;
1211
1212 case DISP_E_NONAMEDARGS:
1213 wsprintf(szBuf, L"%s: Object implementation does not support named arguments.",
1214 szMember);
1215 break;
1216
1217 case DISP_E_UNKNOWNLCID:
1218 wsprintf(szBuf, L"%s: The locale ID is unknown.", szMember);
1219 break;
1220
1221 case DISP_E_PARAMNOTOPTIONAL:
1222 wsprintf(szBuf, L"%s: Missing a required parameter.", szMember);
1223 break;
1224
1225 case DISP_E_PARAMNOTFOUND:
1226 wsprintf(szBuf, L"%s: Argument not found, argument %d.", szMember, uiArgErr);
1227 break;
1228
1229 case DISP_E_TYPEMISMATCH:
1230 wsprintf(szBuf, L"%s: Type mismatch, argument %d.", szMember, uiArgErr);
1231 break;
1232
1233 default:
1234 wsprintf(szBuf, L"%s: Unknown error occured.", szMember);
1235 break;
1236 }
1237
1238 wxLogWarning(szBuf);
d980b3e1
JS
1239}
1240
1241#endif
1242
6b12494d 1243#endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
457e6c54 1244