]>
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__)
19 // Watcom C++ gives a linker error if this is compiled in.
20 // With Borland C++, all samples crash if this is compiled in.
21 #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)
28 #define _FORCENAMELESSUNION
29 #include "wx/msw/private.h"
30 #include "wx/msw/ole/oleutils.h"
31 #include "wx/msw/ole/automtn.h"
34 #include "wx/msw/wince/time.h"
52 #include "wx/datetime.h"
53 #endif // wxUSE_TIMEDATE
55 static void ClearVariant(VARIANTARG
*pvarg
) ;
56 static void ReleaseVariant(VARIANTARG
*pvarg
) ;
57 // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
63 wxAutomationObject::wxAutomationObject(WXIDISPATCH
* dispatchPtr
)
65 m_dispatchPtr
= dispatchPtr
;
68 wxAutomationObject::~wxAutomationObject()
72 ((IDispatch
*)m_dispatchPtr
)->Release();
77 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
79 // For Put/Get, no named arguments are allowed.
80 bool wxAutomationObject::Invoke(const wxString
& member
, int action
,
81 wxVariant
& retValue
, int noArgs
, wxVariant args
[], const wxVariant
* ptrArgs
[]) const
86 // nonConstMember is necessary because the wxString class doesn't have enough consts...
87 wxString
nonConstMember(member
);
89 int ch
= nonConstMember
.Find('.');
92 // Use dot notation to get the next object
93 wxString
member2(nonConstMember
.Left((size_t) ch
));
94 wxString
rest(nonConstMember
.Right(nonConstMember
.length() - ch
- 1));
95 wxAutomationObject obj
;
96 if (!GetObject(obj
, member2
))
98 return obj
.Invoke(rest
, action
, retValue
, noArgs
, args
, ptrArgs
);
102 ClearVariant(& vReturn
);
104 VARIANTARG
* vReturnPtr
= & vReturn
;
106 // Find number of names args
107 int namedArgCount
= 0;
109 for (i
= 0; i
< noArgs
; i
++)
110 if (!INVOKEARG(i
).GetName().IsNull())
115 int namedArgStringCount
= namedArgCount
+ 1;
116 BSTR
* argNames
= new BSTR
[namedArgStringCount
];
117 argNames
[0] = wxConvertStringToOle(member
);
119 // Note that arguments are specified in reverse order
120 // (all totally logical; hey, we're dealing with OLE here.)
123 for (i
= 0; i
< namedArgCount
; i
++)
125 if (!INVOKEARG(i
).GetName().IsNull())
127 argNames
[(namedArgCount
-j
)] = wxConvertStringToOle(INVOKEARG(i
).GetName());
132 // + 1 for the member name, + 1 again in case we're a 'put'
133 DISPID
* dispIds
= new DISPID
[namedArgCount
+ 2];
136 DISPPARAMS dispparams
;
137 unsigned int uiArgErr
;
140 // Get the IDs for the member and its arguments. GetIDsOfNames expects the
141 // member name as the first name, followed by argument names (if any).
142 hr
= ((IDispatch
*)m_dispatchPtr
)->GetIDsOfNames(IID_NULL
, argNames
,
143 1 + namedArgCount
, LOCALE_SYSTEM_DEFAULT
, dispIds
);
146 // ShowException(szMember, hr, NULL, 0);
152 // if doing a property put(ref), we need to adjust the first argument to have a
153 // named arg of DISPID_PROPERTYPUT.
154 if (action
& (DISPATCH_PROPERTYPUT
| DISPATCH_PROPERTYPUTREF
))
157 dispIds
[1] = DISPID_PROPERTYPUT
;
158 vReturnPtr
= (VARIANTARG
*) NULL
;
161 // Convert the wxVariants to VARIANTARGs
162 VARIANTARG
* oleArgs
= new VARIANTARG
[noArgs
];
163 for (i
= 0; i
< noArgs
; i
++)
165 // Again, reverse args
166 if (!wxConvertVariantToOle(INVOKEARG((noArgs
-1) - i
), oleArgs
[i
]))
175 dispparams
.rgdispidNamedArgs
= dispIds
+ 1;
176 dispparams
.rgvarg
= oleArgs
;
177 dispparams
.cArgs
= noArgs
;
178 dispparams
.cNamedArgs
= namedArgCount
;
180 excep
.pfnDeferredFillIn
= NULL
;
182 hr
= ((IDispatch
*)m_dispatchPtr
)->Invoke(dispIds
[0], IID_NULL
, LOCALE_SYSTEM_DEFAULT
,
183 (WORD
)action
, &dispparams
, vReturnPtr
, &excep
, &uiArgErr
);
185 for (i
= 0; i
< namedArgStringCount
; i
++)
187 SysFreeString(argNames
[i
]);
192 for (i
= 0; i
< noArgs
; i
++)
193 ReleaseVariant(& oleArgs
[i
]) ;
198 // display the exception information if appropriate:
199 // ShowException((const char*) member, hr, &excep, uiArgErr);
201 // free exception structure information
202 SysFreeString(excep
.bstrSource
);
203 SysFreeString(excep
.bstrDescription
);
204 SysFreeString(excep
.bstrHelpFile
);
207 ReleaseVariant(vReturnPtr
);
214 // Convert result to wxVariant form
215 wxConvertOleToVariant(vReturn
, retValue
);
216 // Mustn't release the dispatch pointer
217 if (vReturn
.vt
== VT_DISPATCH
)
219 vReturn
.pdispVal
= (IDispatch
*) NULL
;
221 ReleaseVariant(& vReturn
);
227 // Invoke a member function
228 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
, int noArgs
, wxVariant args
[])
230 wxVariant retVariant
;
231 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, args
))
233 retVariant
.MakeNull();
238 wxVariant
wxAutomationObject::CallMethodArray(const wxString
& member
, int noArgs
, const wxVariant
**args
)
240 wxVariant retVariant
;
241 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, NULL
, args
))
243 retVariant
.MakeNull();
248 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
,
249 const wxVariant
& arg1
, const wxVariant
& arg2
,
250 const wxVariant
& arg3
, const wxVariant
& arg4
,
251 const wxVariant
& arg5
, const wxVariant
& arg6
)
253 const wxVariant
** args
= new const wxVariant
*[6];
285 wxVariant retVariant
;
286 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, i
, NULL
, args
))
288 retVariant
.MakeNull();
295 wxVariant
wxAutomationObject::GetPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
297 wxVariant retVariant
;
298 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
300 retVariant
.MakeNull();
304 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
306 wxVariant retVariant
;
307 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
309 retVariant
.MakeNull();
314 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
,
315 const wxVariant
& arg1
, const wxVariant
& arg2
,
316 const wxVariant
& arg3
, const wxVariant
& arg4
,
317 const wxVariant
& arg5
, const wxVariant
& arg6
)
319 const wxVariant
** args
= new const wxVariant
*[6];
351 wxVariant retVariant
;
352 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, i
, NULL
, args
))
354 retVariant
.MakeNull();
360 bool wxAutomationObject::PutProperty(const wxString
& property
, int noArgs
, wxVariant args
[])
362 wxVariant retVariant
;
363 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, args
))
370 bool wxAutomationObject::PutPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
)
372 wxVariant retVariant
;
373 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, NULL
, args
))
380 bool wxAutomationObject::PutProperty(const wxString
& property
,
381 const wxVariant
& arg1
, const wxVariant
& arg2
,
382 const wxVariant
& arg3
, const wxVariant
& arg4
,
383 const wxVariant
& arg5
, const wxVariant
& arg6
)
385 const wxVariant
** args
= new const wxVariant
*[6];
417 wxVariant retVariant
;
418 bool ret
= Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, i
, NULL
, args
);
424 // Uses DISPATCH_PROPERTYGET
425 // and returns a dispatch pointer. The calling code should call Release
426 // on the pointer, though this could be implicit by constructing an wxAutomationObject
427 // with it and letting the destructor call Release.
428 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
430 wxVariant retVariant
;
431 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
433 if (retVariant
.GetType() == wxT("void*"))
435 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
439 return (WXIDISPATCH
*) NULL
;
442 // Uses DISPATCH_PROPERTYGET
443 // and returns a dispatch pointer. The calling code should call Release
444 // on the pointer, though this could be implicit by constructing an wxAutomationObject
445 // with it and letting the destructor call Release.
446 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
448 wxVariant retVariant
;
449 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
451 if (retVariant
.GetType() == wxT("void*"))
453 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
457 return (WXIDISPATCH
*) NULL
;
461 // A way of initialising another wxAutomationObject with a dispatch object
462 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, wxVariant args
[]) const
464 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
467 obj
.SetDispatchPtr(dispatch
);
474 // A way of initialising another wxAutomationObject with a dispatch object
475 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, const wxVariant
**args
) const
477 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
480 obj
.SetDispatchPtr(dispatch
);
487 // Get a dispatch pointer from the current object associated
489 bool wxAutomationObject::GetInstance(const wxString
& classId
) const
495 IUnknown
* pUnk
= NULL
;
497 wxBasicString
unicodeName(classId
.mb_str());
499 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
501 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
505 if (FAILED(GetActiveObject(clsId
, NULL
, &pUnk
)))
507 wxLogWarning(wxT("Cannot find an active object"));
511 if (pUnk
->QueryInterface(IID_IDispatch
, (LPVOID
*) &m_dispatchPtr
) != S_OK
)
513 wxLogWarning(wxT("Cannot find IDispatch interface"));
520 // Get a dispatch pointer from a new object associated
521 // with the given class id
522 bool wxAutomationObject::CreateInstance(const wxString
& classId
) const
529 wxBasicString
unicodeName(classId
.mb_str());
531 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
533 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
537 // start a new copy of Excel, grab the IDispatch interface
538 if (FAILED(CoCreateInstance(clsId
, NULL
, CLSCTX_LOCAL_SERVER
, IID_IDispatch
, (void**)&m_dispatchPtr
)))
540 wxLogWarning(wxT("Cannot start an instance of this class."));
548 WXDLLEXPORT
bool wxConvertVariantToOle(const wxVariant
& variant
, VARIANTARG
& oleVariant
)
550 ClearVariant(&oleVariant
);
551 if (variant
.IsNull())
553 oleVariant
.vt
= VT_NULL
;
557 wxString
type(variant
.GetType());
560 if (type
== wxT("long"))
562 oleVariant
.vt
= VT_I4
;
563 oleVariant
.lVal
= variant
.GetLong() ;
565 // cVal not always present
567 else if (type
== wxT("char"))
569 oleVariant
.vt
=VT_I1
; // Signed Char
570 oleVariant
.cVal
=variant
.GetChar();
573 else if (type
== wxT("double"))
575 oleVariant
.vt
= VT_R8
;
576 oleVariant
.dblVal
= variant
.GetDouble();
578 else if (type
== wxT("bool"))
580 oleVariant
.vt
= VT_BOOL
;
581 // 'bool' required for VC++ 4 apparently
582 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
583 oleVariant
.bool = variant
.GetBool();
585 oleVariant
.boolVal
= variant
.GetBool();
588 else if (type
== wxT("string"))
590 wxString
str( variant
.GetString() );
591 oleVariant
.vt
= VT_BSTR
;
592 oleVariant
.bstrVal
= wxConvertStringToOle(str
);
595 else if (type
== wxT("datetime"))
597 wxDateTime
date( variant
.GetDateTime() );
598 oleVariant
.vt
= VT_DATE
;
600 long dosDateTime
= date
.GetAsDOS();
601 short dosDate
= short((dosDateTime
& 0xFFFF0000) >> 16);
602 short dosTime
= short(dosDateTime
& 0xFFFF);
604 DosDateTimeToVariantTime(dosDate
, dosTime
, & oleVariant
.date
);
607 else if (type
== wxT("void*"))
609 oleVariant
.vt
= VT_DISPATCH
;
610 oleVariant
.pdispVal
= (IDispatch
*) variant
.GetVoidPtr();
612 else if (type
== wxT("list") || type
== wxT("stringlist"))
614 oleVariant
.vt
= VT_VARIANT
| VT_ARRAY
;
617 SAFEARRAYBOUND saBound
;
618 VARIANTARG
*pvargBase
;
622 int iCount
= variant
.GetCount();
625 saBound
.cElements
= iCount
;
627 psa
= SafeArrayCreate(VT_VARIANT
, 1, &saBound
);
631 SafeArrayAccessData(psa
, (void**)&pvargBase
);
634 for (i
= 0; i
< iCount
; i
++)
636 // copy each string in the list of strings
637 wxVariant
eachVariant(variant
[i
]);
638 if (!wxConvertVariantToOle(eachVariant
, * pvarg
))
640 // memory failure: back out and free strings alloc'ed up to
641 // now, and then the array itself.
643 for (j
= 0; j
< i
; j
++)
645 SysFreeString(pvarg
->bstrVal
);
648 SafeArrayDestroy(psa
);
654 SafeArrayUnaccessData(psa
);
656 oleVariant
.parray
= psa
;
660 oleVariant
.vt
= VT_NULL
;
667 #define VT_TYPEMASK 0xfff
670 WXDLLEXPORT
bool wxConvertOleToVariant(const VARIANTARG
& oleVariant
, wxVariant
& variant
)
672 switch (oleVariant
.vt
& VT_TYPEMASK
)
676 wxString
str(wxConvertStringFromOle(oleVariant
.bstrVal
));
683 unsigned short dosDate
= 0;
684 unsigned short dosTime
= 0;
685 VariantTimeToDosDateTime(oleVariant
.date
, & dosDate
, & dosTime
);
687 long dosDateTime
= (dosDate
<< 16) || dosTime
;
689 date
.SetFromDOS(dosDateTime
);
696 variant
= (long) oleVariant
.lVal
;
701 variant
= (long) oleVariant
.iVal
;
707 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC
708 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
709 variant
= (long) (oleVariant
.bool != 0);
711 variant
= (bool) (oleVariant
.bool != 0);
714 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type
715 variant
= (long) (oleVariant
.boolVal
!= 0);
717 variant
= (bool) (oleVariant
.boolVal
!= 0);
724 variant
= oleVariant
.dblVal
;
731 int cDims
, cElements
, i
;
734 // Iterate the dimensions: number of elements is x*y*z
735 for (cDims
= 0, cElements
= 1;
736 cDims
< oleVariant
.parray
->cDims
; cDims
++)
737 cElements
*= oleVariant
.parray
->rgsabound
[cDims
].cElements
;
739 // Get a pointer to the data
740 HRESULT hr
= SafeArrayAccessData(oleVariant
.parray
, (void HUGEP
* FAR
*) & pvdata
);
744 for (i
= 0; i
< cElements
; i
++)
746 VARIANTARG
& oleElement
= pvdata
[i
];
748 if (!wxConvertOleToVariant(oleElement
, vElement
))
751 variant
.Append(vElement
);
753 SafeArrayUnaccessData(oleVariant
.parray
);
758 variant
= (void*) oleVariant
.pdispVal
;
768 break; // Ignore Empty Variant, used only during destruction of objects
772 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type"));
782 * Zeros a variant structure without regard to current contents
784 static void ClearVariant(VARIANTARG
*pvarg
)
786 pvarg
->vt
= VT_EMPTY
;
787 pvarg
->wReserved1
= 0;
788 pvarg
->wReserved2
= 0;
789 pvarg
->wReserved3
= 0;
796 * Clears a particular variant structure and releases any external objects
797 * or memory contained in the variant. Supports the data types listed above.
799 static void ReleaseVariant(VARIANTARG
*pvarg
)
802 VARIANTARG _huge
*pvargArray
;
803 long lLBound
, lUBound
, l
;
805 vt
= (VARTYPE
)(pvarg
->vt
& 0xfff); // mask off flags
807 // check if an array. If so, free its contents, then the array itself.
808 if (V_ISARRAY(pvarg
))
810 // variant arrays are all this routine currently knows about. Since a
811 // variant can contain anything (even other arrays), call ourselves
813 if (vt
== VT_VARIANT
)
815 SafeArrayGetLBound(pvarg
->parray
, 1, &lLBound
);
816 SafeArrayGetUBound(pvarg
->parray
, 1, &lUBound
);
818 if (lUBound
> lLBound
)
822 SafeArrayAccessData(pvarg
->parray
, (void**)&pvargArray
);
824 for (l
= 0; l
< lUBound
; l
++)
826 ReleaseVariant(pvargArray
);
830 SafeArrayUnaccessData(pvarg
->parray
);
835 wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type"));
838 // Free the array itself.
839 SafeArrayDestroy(pvarg
->parray
);
847 pvarg
->pdispVal
->Release();
851 SysFreeString(pvarg
->bstrVal
);
858 case VT_ERROR
: // to avoid erroring on an error return from Excel
860 // no work for these types
864 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
874 void ShowException(LPOLESTR szMember
, HRESULT hr
, EXCEPINFO
*pexcep
, unsigned int uiArgErr
)
878 switch (GetScode(hr
))
880 case DISP_E_UNKNOWNNAME
:
881 wsprintf(szBuf
, L
"%s: Unknown name or named argument.", szMember
);
884 case DISP_E_BADPARAMCOUNT
:
885 wsprintf(szBuf
, L
"%s: Incorrect number of arguments.", szMember
);
888 case DISP_E_EXCEPTION
:
889 wsprintf(szBuf
, L
"%s: Error %d: ", szMember
, pexcep
->wCode
);
890 if (pexcep
->bstrDescription
!= NULL
)
891 lstrcat(szBuf
, pexcep
->bstrDescription
);
893 lstrcat(szBuf
, L
"<<No Description>>");
896 case DISP_E_MEMBERNOTFOUND
:
897 wsprintf(szBuf
, L
"%s: method or property not found.", szMember
);
900 case DISP_E_OVERFLOW
:
901 wsprintf(szBuf
, L
"%s: Overflow while coercing argument values.", szMember
);
904 case DISP_E_NONAMEDARGS
:
905 wsprintf(szBuf
, L
"%s: Object implementation does not support named arguments.",
909 case DISP_E_UNKNOWNLCID
:
910 wsprintf(szBuf
, L
"%s: The locale ID is unknown.", szMember
);
913 case DISP_E_PARAMNOTOPTIONAL
:
914 wsprintf(szBuf
, L
"%s: Missing a required parameter.", szMember
);
917 case DISP_E_PARAMNOTFOUND
:
918 wsprintf(szBuf
, L
"%s: Argument not found, argument %d.", szMember
, uiArgErr
);
921 case DISP_E_TYPEMISMATCH
:
922 wsprintf(szBuf
, L
"%s: Type mismatch, argument %d.", szMember
, uiArgErr
);
926 wsprintf(szBuf
, L
"%s: Unknown error occurred.", szMember
);
935 #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)