]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/automtn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/ole/automtn.cpp
3 // Purpose: OLE automation utilities
4 // Author: Julian Smart
8 // Copyright: (c) 1998, Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
15 #if defined(__BORLANDC__)
21 // Watcom C++ gives a linker error if this is compiled in.
22 // With Borland C++, all samples crash if this is compiled in.
23 #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
25 #define _FORCENAMELESSUNION
27 #include "wx/msw/private.h"
28 #include "wx/msw/ole/oleutils.h"
29 #include "wx/msw/ole/automtn.h"
33 #include "wx/msw/wince/time.h"
51 #include "wx/datetime.h"
52 #endif // wxUSE_TIMEDATE
54 static void ClearVariant(VARIANTARG
*pvarg
) ;
55 static void ReleaseVariant(VARIANTARG
*pvarg
) ;
56 // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
62 wxAutomationObject::wxAutomationObject(WXIDISPATCH
* dispatchPtr
)
64 m_dispatchPtr
= dispatchPtr
;
67 wxAutomationObject::~wxAutomationObject()
71 ((IDispatch
*)m_dispatchPtr
)->Release();
76 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
78 // For Put/Get, no named arguments are allowed.
79 bool wxAutomationObject::Invoke(const wxString
& member
, int action
,
80 wxVariant
& retValue
, int noArgs
, wxVariant args
[], const wxVariant
* ptrArgs
[]) const
85 // nonConstMember is necessary because the wxString class doesn't have enough consts...
86 wxString
nonConstMember(member
);
88 int ch
= nonConstMember
.Find('.');
91 // Use dot notation to get the next object
92 wxString
member2(nonConstMember
.Left((size_t) ch
));
93 wxString
rest(nonConstMember
.Right(nonConstMember
.Length() - ch
- 1));
94 wxAutomationObject obj
;
95 if (!GetObject(obj
, member2
))
97 return obj
.Invoke(rest
, action
, retValue
, noArgs
, args
, ptrArgs
);
101 ClearVariant(& vReturn
);
103 VARIANTARG
* vReturnPtr
= & vReturn
;
105 // Find number of names args
106 int namedArgCount
= 0;
108 for (i
= 0; i
< noArgs
; i
++)
109 if (!INVOKEARG(i
).GetName().IsNull())
114 int namedArgStringCount
= namedArgCount
+ 1;
115 BSTR
* argNames
= new BSTR
[namedArgStringCount
];
116 argNames
[0] = wxConvertStringToOle(member
);
118 // Note that arguments are specified in reverse order
119 // (all totally logical; hey, we're dealing with OLE here.)
122 for (i
= 0; i
< namedArgCount
; i
++)
124 if (!INVOKEARG(i
).GetName().IsNull())
126 argNames
[(namedArgCount
-j
)] = wxConvertStringToOle(INVOKEARG(i
).GetName());
131 // + 1 for the member name, + 1 again in case we're a 'put'
132 DISPID
* dispIds
= new DISPID
[namedArgCount
+ 2];
135 DISPPARAMS dispparams
;
136 unsigned int uiArgErr
;
139 // Get the IDs for the member and its arguments. GetIDsOfNames expects the
140 // member name as the first name, followed by argument names (if any).
141 hr
= ((IDispatch
*)m_dispatchPtr
)->GetIDsOfNames(IID_NULL
, argNames
,
142 1 + namedArgCount
, LOCALE_SYSTEM_DEFAULT
, dispIds
);
145 // ShowException(szMember, hr, NULL, 0);
151 // if doing a property put(ref), we need to adjust the first argument to have a
152 // named arg of DISPID_PROPERTYPUT.
153 if (action
& (DISPATCH_PROPERTYPUT
| DISPATCH_PROPERTYPUTREF
))
156 dispIds
[1] = DISPID_PROPERTYPUT
;
157 vReturnPtr
= (VARIANTARG
*) NULL
;
160 // Convert the wxVariants to VARIANTARGs
161 VARIANTARG
* oleArgs
= new VARIANTARG
[noArgs
];
162 for (i
= 0; i
< noArgs
; i
++)
164 // Again, reverse args
165 if (!wxConvertVariantToOle(INVOKEARG((noArgs
-1) - i
), oleArgs
[i
]))
174 dispparams
.rgdispidNamedArgs
= dispIds
+ 1;
175 dispparams
.rgvarg
= oleArgs
;
176 dispparams
.cArgs
= noArgs
;
177 dispparams
.cNamedArgs
= namedArgCount
;
179 excep
.pfnDeferredFillIn
= NULL
;
181 hr
= ((IDispatch
*)m_dispatchPtr
)->Invoke(dispIds
[0], IID_NULL
, LOCALE_SYSTEM_DEFAULT
,
182 (WORD
)action
, &dispparams
, vReturnPtr
, &excep
, &uiArgErr
);
184 for (i
= 0; i
< namedArgStringCount
; i
++)
186 SysFreeString(argNames
[i
]);
191 for (i
= 0; i
< noArgs
; i
++)
192 ReleaseVariant(& oleArgs
[i
]) ;
197 // display the exception information if appropriate:
198 // ShowException((const char*) member, hr, &excep, uiArgErr);
200 // free exception structure information
201 SysFreeString(excep
.bstrSource
);
202 SysFreeString(excep
.bstrDescription
);
203 SysFreeString(excep
.bstrHelpFile
);
206 ReleaseVariant(vReturnPtr
);
213 // Convert result to wxVariant form
214 wxConvertOleToVariant(vReturn
, retValue
);
215 // Mustn't release the dispatch pointer
216 if (vReturn
.vt
== VT_DISPATCH
)
218 vReturn
.pdispVal
= (IDispatch
*) NULL
;
220 ReleaseVariant(& vReturn
);
226 // Invoke a member function
227 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
, int noArgs
, wxVariant args
[])
229 wxVariant retVariant
;
230 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, args
))
232 retVariant
.MakeNull();
237 wxVariant
wxAutomationObject::CallMethodArray(const wxString
& member
, int noArgs
, const wxVariant
**args
)
239 wxVariant retVariant
;
240 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, NULL
, args
))
242 retVariant
.MakeNull();
247 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
,
248 const wxVariant
& arg1
, const wxVariant
& arg2
,
249 const wxVariant
& arg3
, const wxVariant
& arg4
,
250 const wxVariant
& arg5
, const wxVariant
& arg6
)
252 const wxVariant
** args
= new const wxVariant
*[6];
284 wxVariant retVariant
;
285 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, i
, NULL
, args
))
287 retVariant
.MakeNull();
294 wxVariant
wxAutomationObject::GetPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
296 wxVariant retVariant
;
297 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
299 retVariant
.MakeNull();
303 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
305 wxVariant retVariant
;
306 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
308 retVariant
.MakeNull();
313 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
,
314 const wxVariant
& arg1
, const wxVariant
& arg2
,
315 const wxVariant
& arg3
, const wxVariant
& arg4
,
316 const wxVariant
& arg5
, const wxVariant
& arg6
)
318 const wxVariant
** args
= new const wxVariant
*[6];
350 wxVariant retVariant
;
351 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, i
, NULL
, args
))
353 retVariant
.MakeNull();
359 bool wxAutomationObject::PutProperty(const wxString
& property
, int noArgs
, wxVariant args
[])
361 wxVariant retVariant
;
362 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, args
))
369 bool wxAutomationObject::PutPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
)
371 wxVariant retVariant
;
372 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, NULL
, args
))
379 bool wxAutomationObject::PutProperty(const wxString
& property
,
380 const wxVariant
& arg1
, const wxVariant
& arg2
,
381 const wxVariant
& arg3
, const wxVariant
& arg4
,
382 const wxVariant
& arg5
, const wxVariant
& arg6
)
384 const wxVariant
** args
= new const wxVariant
*[6];
416 wxVariant retVariant
;
417 bool ret
= Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, i
, NULL
, args
);
423 // Uses DISPATCH_PROPERTYGET
424 // and returns a dispatch pointer. The calling code should call Release
425 // on the pointer, though this could be implicit by constructing an wxAutomationObject
426 // with it and letting the destructor call Release.
427 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
429 wxVariant retVariant
;
430 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
432 if (retVariant
.GetType() == wxT("void*"))
434 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
438 return (WXIDISPATCH
*) NULL
;
441 // Uses DISPATCH_PROPERTYGET
442 // and returns a dispatch pointer. The calling code should call Release
443 // on the pointer, though this could be implicit by constructing an wxAutomationObject
444 // with it and letting the destructor call Release.
445 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
447 wxVariant retVariant
;
448 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
450 if (retVariant
.GetType() == wxT("void*"))
452 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
456 return (WXIDISPATCH
*) NULL
;
460 // A way of initialising another wxAutomationObject with a dispatch object
461 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, wxVariant args
[]) const
463 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
466 obj
.SetDispatchPtr(dispatch
);
473 // A way of initialising another wxAutomationObject with a dispatch object
474 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, const wxVariant
**args
) const
476 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
479 obj
.SetDispatchPtr(dispatch
);
486 // Get a dispatch pointer from the current object associated
488 bool wxAutomationObject::GetInstance(const wxString
& classId
) const
494 IUnknown
* pUnk
= NULL
;
496 wxBasicString
unicodeName(classId
.mb_str());
498 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
500 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
504 if (FAILED(GetActiveObject(clsId
, NULL
, &pUnk
)))
506 wxLogWarning(wxT("Cannot find an active object"));
510 if (pUnk
->QueryInterface(IID_IDispatch
, (LPVOID
*) &m_dispatchPtr
) != S_OK
)
512 wxLogWarning(wxT("Cannot find IDispatch interface"));
519 // Get a dispatch pointer from a new object associated
520 // with the given class id
521 bool wxAutomationObject::CreateInstance(const wxString
& classId
) const
528 wxBasicString
unicodeName(classId
.mb_str());
530 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
532 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
536 // start a new copy of Excel, grab the IDispatch interface
537 if (FAILED(CoCreateInstance(clsId
, NULL
, CLSCTX_LOCAL_SERVER
, IID_IDispatch
, (void**)&m_dispatchPtr
)))
539 wxLogWarning(wxT("Cannot start an instance of this class."));
547 bool wxConvertVariantToOle(const wxVariant
& variant
, VARIANTARG
& oleVariant
)
549 ClearVariant(&oleVariant
);
550 if (variant
.IsNull())
552 oleVariant
.vt
= VT_NULL
;
556 wxString
type(variant
.GetType());
559 if (type
== wxT("long"))
561 oleVariant
.vt
= VT_I4
;
562 oleVariant
.lVal
= variant
.GetLong() ;
564 // cVal not always present
566 else if (type
== wxT("char"))
568 oleVariant
.vt
=VT_I1
; // Signed Char
569 oleVariant
.cVal
=variant
.GetChar();
572 else if (type
== wxT("double"))
574 oleVariant
.vt
= VT_R8
;
575 oleVariant
.dblVal
= variant
.GetDouble();
577 else if (type
== wxT("bool"))
579 oleVariant
.vt
= VT_BOOL
;
580 // 'bool' required for VC++ 4 apparently
581 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
582 oleVariant
.bool = variant
.GetBool();
584 oleVariant
.boolVal
= variant
.GetBool();
587 else if (type
== wxT("string"))
589 wxString
str( variant
.GetString() );
590 oleVariant
.vt
= VT_BSTR
;
591 oleVariant
.bstrVal
= wxConvertStringToOle(str
);
594 else if (type
== wxT("datetime"))
596 wxDateTime
date( variant
.GetDateTime() );
597 oleVariant
.vt
= VT_DATE
;
599 long dosDateTime
= date
.GetAsDOS();
600 short dosDate
= short((dosDateTime
& 0xFFFF0000) >> 16);
601 short dosTime
= short(dosDateTime
& 0xFFFF);
603 DosDateTimeToVariantTime(dosDate
, dosTime
, & oleVariant
.date
);
606 else if (type
== wxT("void*"))
608 oleVariant
.vt
= VT_DISPATCH
;
609 oleVariant
.pdispVal
= (IDispatch
*) variant
.GetVoidPtr();
611 else if (type
== wxT("list") || type
== wxT("stringlist"))
613 oleVariant
.vt
= VT_VARIANT
| VT_ARRAY
;
616 SAFEARRAYBOUND saBound
;
617 VARIANTARG
*pvargBase
;
621 int iCount
= variant
.GetCount();
624 saBound
.cElements
= iCount
;
626 psa
= SafeArrayCreate(VT_VARIANT
, 1, &saBound
);
630 SafeArrayAccessData(psa
, (void**)&pvargBase
);
633 for (i
= 0; i
< iCount
; i
++)
635 // copy each string in the list of strings
636 wxVariant
eachVariant(variant
[i
]);
637 if (!wxConvertVariantToOle(eachVariant
, * pvarg
))
639 // memory failure: back out and free strings alloc'ed up to
640 // now, and then the array itself.
642 for (j
= 0; j
< i
; j
++)
644 SysFreeString(pvarg
->bstrVal
);
647 SafeArrayDestroy(psa
);
653 SafeArrayUnaccessData(psa
);
655 oleVariant
.parray
= psa
;
659 oleVariant
.vt
= VT_NULL
;
666 #define VT_TYPEMASK 0xfff
669 bool wxConvertOleToVariant(const VARIANTARG
& oleVariant
, wxVariant
& variant
)
671 switch (oleVariant
.vt
& VT_TYPEMASK
)
675 wxString
str(wxConvertStringFromOle(oleVariant
.bstrVal
));
682 unsigned short dosDate
= 0;
683 unsigned short dosTime
= 0;
684 VariantTimeToDosDateTime(oleVariant
.date
, & dosDate
, & dosTime
);
686 long dosDateTime
= (dosDate
<< 16) || dosTime
;
688 date
.SetFromDOS(dosDateTime
);
695 variant
= (long) oleVariant
.lVal
;
700 variant
= (long) oleVariant
.iVal
;
706 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC
707 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
708 variant
= (long) (oleVariant
.bool != 0);
710 variant
= (bool) (oleVariant
.bool != 0);
713 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
714 variant
= (long) (oleVariant
.boolVal
!= 0);
716 variant
= (bool) (oleVariant
.boolVal
!= 0);
723 variant
= oleVariant
.dblVal
;
730 int cDims
, cElements
, i
;
733 // Iterate the dimensions: number of elements is x*y*z
734 for (cDims
= 0, cElements
= 1;
735 cDims
< oleVariant
.parray
->cDims
; cDims
++)
736 cElements
*= oleVariant
.parray
->rgsabound
[cDims
].cElements
;
738 // Get a pointer to the data
739 HRESULT hr
= SafeArrayAccessData(oleVariant
.parray
, (void HUGEP
* FAR
*) & pvdata
);
743 for (i
= 0; i
< cElements
; i
++)
745 VARIANTARG
& oleElement
= pvdata
[i
];
747 if (!wxConvertOleToVariant(oleElement
, vElement
))
750 variant
.Append(vElement
);
752 SafeArrayUnaccessData(oleVariant
.parray
);
757 variant
= (void*) oleVariant
.pdispVal
;
767 break; // Ignore Empty Variant, used only during destruction of objects
771 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type"));
781 * Zeros a variant structure without regard to current contents
783 static void ClearVariant(VARIANTARG
*pvarg
)
785 pvarg
->vt
= VT_EMPTY
;
786 pvarg
->wReserved1
= 0;
787 pvarg
->wReserved2
= 0;
788 pvarg
->wReserved3
= 0;
795 * Clears a particular variant structure and releases any external objects
796 * or memory contained in the variant. Supports the data types listed above.
798 static void ReleaseVariant(VARIANTARG
*pvarg
)
801 VARIANTARG _huge
*pvargArray
;
802 long lLBound
, lUBound
, l
;
804 vt
= (VARTYPE
)(pvarg
->vt
& 0xfff); // mask off flags
806 // check if an array. If so, free its contents, then the array itself.
807 if (V_ISARRAY(pvarg
))
809 // variant arrays are all this routine currently knows about. Since a
810 // variant can contain anything (even other arrays), call ourselves
812 if (vt
== VT_VARIANT
)
814 SafeArrayGetLBound(pvarg
->parray
, 1, &lLBound
);
815 SafeArrayGetUBound(pvarg
->parray
, 1, &lUBound
);
817 if (lUBound
> lLBound
)
821 SafeArrayAccessData(pvarg
->parray
, (void**)&pvargArray
);
823 for (l
= 0; l
< lUBound
; l
++)
825 ReleaseVariant(pvargArray
);
829 SafeArrayUnaccessData(pvarg
->parray
);
834 wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type"));
837 // Free the array itself.
838 SafeArrayDestroy(pvarg
->parray
);
846 pvarg
->pdispVal
->Release();
850 SysFreeString(pvarg
->bstrVal
);
856 case VT_ERROR
: // to avoid erroring on an error return from Excel
857 // no work for these types
861 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
871 void ShowException(LPOLESTR szMember
, HRESULT hr
, EXCEPINFO
*pexcep
, unsigned int uiArgErr
)
875 switch (GetScode(hr
))
877 case DISP_E_UNKNOWNNAME
:
878 wsprintf(szBuf
, L
"%s: Unknown name or named argument.", szMember
);
881 case DISP_E_BADPARAMCOUNT
:
882 wsprintf(szBuf
, L
"%s: Incorrect number of arguments.", szMember
);
885 case DISP_E_EXCEPTION
:
886 wsprintf(szBuf
, L
"%s: Error %d: ", szMember
, pexcep
->wCode
);
887 if (pexcep
->bstrDescription
!= NULL
)
888 lstrcat(szBuf
, pexcep
->bstrDescription
);
890 lstrcat(szBuf
, L
"<<No Description>>");
893 case DISP_E_MEMBERNOTFOUND
:
894 wsprintf(szBuf
, L
"%s: method or property not found.", szMember
);
897 case DISP_E_OVERFLOW
:
898 wsprintf(szBuf
, L
"%s: Overflow while coercing argument values.", szMember
);
901 case DISP_E_NONAMEDARGS
:
902 wsprintf(szBuf
, L
"%s: Object implementation does not support named arguments.",
906 case DISP_E_UNKNOWNLCID
:
907 wsprintf(szBuf
, L
"%s: The locale ID is unknown.", szMember
);
910 case DISP_E_PARAMNOTOPTIONAL
:
911 wsprintf(szBuf
, L
"%s: Missing a required parameter.", szMember
);
914 case DISP_E_PARAMNOTFOUND
:
915 wsprintf(szBuf
, L
"%s: Argument not found, argument %d.", szMember
, uiArgErr
);
918 case DISP_E_TYPEMISMATCH
:
919 wsprintf(szBuf
, L
"%s: Type mismatch, argument %d.", szMember
, uiArgErr
);
923 wsprintf(szBuf
, L
"%s: Unknown error occurred.", szMember
);
932 #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)