]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/automtn.cpp
Do not break twice.
[wxWidgets.git] / src / msw / ole / automtn.cpp
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
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
23 #include "wx/defs.h"
24
25 // Watcom C++ gives a linker error if this is compiled in.
26 // With Borland C++, all samples crash if this is compiled in.
27 #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
28
29 #define _FORCENAMELESSUNION
30 #include "wx/log.h"
31 #include "wx/msw/private.h"
32 #include "wx/msw/ole/oleutils.h"
33 #include "wx/msw/ole/automtn.h"
34 #include "wx/math.h"
35
36 #ifdef __WXWINCE__
37 #include "wx/msw/wince/time.h"
38 #else
39 #include <time.h>
40 #endif
41
42 #include <wtypes.h>
43 #include <unknwn.h>
44
45 #include <ole2.h>
46 #define _huge
47
48 #ifndef __WXWINCE__
49 #include <ole2ver.h>
50 #endif
51
52 #include <oleauto.h>
53
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
63 static int rgMonthDays[13] =
64 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
65
66 #if wxUSE_DATETIME
67 #include "wx/datetime.h"
68
69 static BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
70 WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest);
71 static BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest);
72 #endif // wxUSE_TIMEDATE
73
74 static void ClearVariant(VARIANTARG *pvarg) ;
75 static void ReleaseVariant(VARIANTARG *pvarg) ;
76 // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
77
78 /*
79 * wxAutomationObject
80 */
81
82 wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr)
83 {
84 m_dispatchPtr = dispatchPtr;
85 }
86
87 wxAutomationObject::~wxAutomationObject()
88 {
89 if (m_dispatchPtr)
90 {
91 ((IDispatch*)m_dispatchPtr)->Release();
92 m_dispatchPtr = NULL;
93 }
94 }
95
96 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
97
98 // For Put/Get, no named arguments are allowed.
99 bool wxAutomationObject::Invoke(const wxString& member, int action,
100 wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const
101 {
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())
130 {
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;
189 delete[] oleArgs;
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,
202 (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
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);
241 }
242 }
243 return true;
244 }
245
246 // Invoke a member function
247 wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[])
248 {
249 wxVariant retVariant;
250 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args))
251 {
252 retVariant.MakeNull();
253 }
254 return retVariant;
255 }
256
257 wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args)
258 {
259 wxVariant retVariant;
260 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args))
261 {
262 retVariant.MakeNull();
263 }
264 return retVariant;
265 }
266
267 wxVariant wxAutomationObject::CallMethod(const wxString& member,
268 const wxVariant& arg1, const wxVariant& arg2,
269 const wxVariant& arg3, const wxVariant& arg4,
270 const wxVariant& arg5, const wxVariant& arg6)
271 {
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;
311 }
312
313 // Get/Set property
314 wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const
315 {
316 wxVariant retVariant;
317 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
318 {
319 retVariant.MakeNull();
320 }
321 return retVariant;
322 }
323 wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const
324 {
325 wxVariant retVariant;
326 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
327 {
328 retVariant.MakeNull();
329 }
330 return retVariant;
331 }
332
333 wxVariant wxAutomationObject::GetProperty(const wxString& property,
334 const wxVariant& arg1, const wxVariant& arg2,
335 const wxVariant& arg3, const wxVariant& arg4,
336 const wxVariant& arg5, const wxVariant& arg6)
337 {
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;
377 }
378
379 bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[])
380 {
381 wxVariant retVariant;
382 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args))
383 {
384 return false;
385 }
386 return true;
387 }
388
389 bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args)
390 {
391 wxVariant retVariant;
392 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args))
393 {
394 return false;
395 }
396 return true;
397 }
398
399 bool wxAutomationObject::PutProperty(const wxString& property,
400 const wxVariant& arg1, const wxVariant& arg2,
401 const wxVariant& arg3, const wxVariant& arg4,
402 const wxVariant& arg5, const wxVariant& arg6)
403 {
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;
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.
447 WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, wxVariant args[]) const
448 {
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;
459 }
460
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.
465 WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, const wxVariant **args) const
466 {
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;
477 }
478
479
480 // A way of initialising another wxAutomationObject with a dispatch object
481 bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, wxVariant args[]) const
482 {
483 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
484 if (dispatch)
485 {
486 obj.SetDispatchPtr(dispatch);
487 return true;
488 }
489 else
490 return false;
491 }
492
493 // A way of initialising another wxAutomationObject with a dispatch object
494 bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, const wxVariant **args) const
495 {
496 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
497 if (dispatch)
498 {
499 obj.SetDispatchPtr(dispatch);
500 return true;
501 }
502 else
503 return false;
504 }
505
506 // Get a dispatch pointer from the current object associated
507 // with a class id
508 bool wxAutomationObject::GetInstance(const wxString& classId) const
509 {
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;
537 }
538
539 // Get a dispatch pointer from a new object associated
540 // with the given class id
541 bool wxAutomationObject::CreateInstance(const wxString& classId) const
542 {
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;
564 }
565
566
567 bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
568 {
569 ClearVariant(&oleVariant);
570 if (variant.IsNull())
571 {
572 oleVariant.vt = VT_NULL;
573 return true;
574 }
575
576 wxString type(variant.GetType());
577
578
579 if (type == wxT("long"))
580 {
581 oleVariant.vt = VT_I4;
582 oleVariant.lVal = variant.GetLong() ;
583 }
584 // cVal not always present
585 #ifndef __GNUWIN32__
586 else if (type == wxT("char"))
587 {
588 oleVariant.vt=VT_I1; // Signed Char
589 oleVariant.cVal=variant.GetChar();
590 }
591 #endif
592 else if (type == wxT("double"))
593 {
594 oleVariant.vt = VT_R8;
595 oleVariant.dblVal = variant.GetDouble();
596 }
597 else if (type == wxT("bool"))
598 {
599 oleVariant.vt = VT_BOOL;
600 // 'bool' required for VC++ 4 apparently
601 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
602 oleVariant.bool = variant.GetBool();
603 #else
604 oleVariant.boolVal = variant.GetBool();
605 #endif
606 }
607 else if (type == wxT("string"))
608 {
609 wxString str( variant.GetString() );
610 oleVariant.vt = VT_BSTR;
611 oleVariant.bstrVal = wxConvertStringToOle(str);
612 }
613 #if wxUSE_DATETIME
614 else if (type == wxT("datetime"))
615 {
616 wxDateTime date( variant.GetDateTime() );
617 oleVariant.vt = VT_DATE;
618
619 if (!OleDateFromTm((WORD)date.GetYear(), date.GetMonth(), date.GetDay(),
620 date.GetHour(), date.GetMinute(), date.GetSecond(), oleVariant.date))
621 return false;
622 }
623 #endif
624 else if (type == wxT("void*"))
625 {
626 oleVariant.vt = VT_DISPATCH;
627 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
628 }
629 else if (type == wxT("list") || type == wxT("stringlist"))
630 {
631 oleVariant.vt = VT_VARIANT | VT_ARRAY;
632
633 SAFEARRAY *psa;
634 SAFEARRAYBOUND saBound;
635 VARIANTARG *pvargBase;
636 VARIANTARG *pvarg;
637 int i, j;
638
639 int iCount = variant.GetCount();
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
654 wxVariant eachVariant(variant[i]);
655 if (!wxConvertVariantToOle(eachVariant, * pvarg))
656 {
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);
672
673 oleVariant.parray = psa;
674 }
675 else
676 {
677 oleVariant.vt = VT_NULL;
678 return false;
679 }
680 return true;
681 }
682
683 #ifndef VT_TYPEMASK
684 #define VT_TYPEMASK 0xfff
685 #endif
686
687 bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
688 {
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 {
699 #if wxUSE_DATETIME
700 struct tm tmTemp;
701 if (!TmFromOleDate(oleVariant.date, tmTemp))
702 return false;
703
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);
710
711 variant = date;
712 #endif
713
714 break;
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 {
729 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC
730 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
731 variant = (long) (oleVariant.bool != 0);
732 #else
733 variant = (bool) (oleVariant.bool != 0);
734 #endif
735 #else
736 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
737 variant = (long) (oleVariant.boolVal != 0);
738 #else
739 variant = (bool) (oleVariant.boolVal != 0);
740 #endif
741 #endif
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;
799 }
800
801 BSTR wxConvertStringToOle(const wxString& str)
802 {
803 /*
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];
810 */
811 wxBasicString bstr(str.mb_str());
812 return bstr.Get();
813 }
814
815 wxString wxConvertStringFromOle(BSTR bStr)
816 {
817 #if wxUSE_UNICODE
818 wxString str(bStr);
819 #else
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;
825 #endif
826 return str;
827 }
828
829 // ----------------------------------------------------------------------------
830 // wxBasicString
831 // ----------------------------------------------------------------------------
832
833 // ctor takes an ANSI string and transforms it to Unicode
834 wxBasicString::wxBasicString(const char *sz)
835 {
836 Init(sz);
837 }
838
839 // ctor takes an ANSI or Unicode string and transforms it to Unicode
840 wxBasicString::wxBasicString(const wxString& str)
841 {
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
852 void 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
861
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 }
870 }
871
872 // dtor frees memory
873 wxBasicString::~wxBasicString()
874 {
875 delete [] m_wzBuf;
876 }
877
878 /////////////////////////////////////////////////////////////////////////////
879 // COleDateTime class HELPERS - implementation
880
881 BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
882 WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest)
883 {
884 // Validate year and month (ignore day of week and milliseconds)
885 if (wYear > 9999 || wMonth < 1 || wMonth > 12)
886 return FALSE;
887
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);
891
892 int nDaysInMonth =
893 rgMonthDays[wMonth] - rgMonthDays[wMonth-1] +
894 ((bLeapYear && wDay == 29 && wMonth == 2) ? 1 : 0);
895
896 // Finish validating the date
897 if (wDay < 1 || wDay > nDaysInMonth ||
898 wHour > 23 || wMinute > 59 ||
899 wSecond > 59)
900 {
901 return FALSE;
902 }
903
904 // Cache the date in days and time in fractional days
905 long nDate;
906 double dblTime;
907
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;
911
912 // If leap year and it's before March, subtract 1:
913 if (wMonth <= 2 && bLeapYear)
914 --nDate;
915
916 // Offset so that 12/30/1899 is 0
917 nDate -= 693959L;
918
919 dblTime = (((long)wHour * 3600L) + // hrs in seconds
920 ((long)wMinute * 60L) + // mins in seconds
921 ((long)wSecond)) / 86400.;
922
923 dtDest = (double) nDate + ((nDate >= 0) ? dblTime : -dblTime);
924
925 return TRUE;
926 }
927
928 BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest)
929 {
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]);
1038
1039 DoTime:
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;
1051 }
1052
1053 // this function is not used
1054 #if 0
1055 void TmConvertToStandardFormat(struct tm& tmSrc)
1056 {
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
1062 }
1063
1064 double DoubleFromDate(DATE dt)
1065 {
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);
1074 }
1075
1076 DATE DateFromDouble(double dbl)
1077 {
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);
1086 }
1087 #endif // 0
1088
1089 /*
1090 * ClearVariant
1091 *
1092 * Zeros a variant structure without regard to current contents
1093 */
1094 static void ClearVariant(VARIANTARG *pvarg)
1095 {
1096 pvarg->vt = VT_EMPTY;
1097 pvarg->wReserved1 = 0;
1098 pvarg->wReserved2 = 0;
1099 pvarg->wReserved3 = 0;
1100 pvarg->lVal = 0;
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 */
1109 static void ReleaseVariant(VARIANTARG *pvarg)
1110 {
1111 VARTYPE vt;
1112 VARIANTARG _huge *pvargArray;
1113 long lLBound, lUBound, l;
1114
1115 vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags
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);
1178 }
1179
1180 #if 0
1181
1182 void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr)
1183 {
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);
1239 }
1240
1241 #endif
1242
1243 #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
1244