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