]>
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 // With Borland C++, all samples crash if this is compiled in.
20 #if (defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) || defined(__CYGWIN10__)
21 #undef wxUSE_OLE_AUTOMATION
22 #define wxUSE_OLE_AUTOMATION 0
25 #if wxUSE_OLE_AUTOMATION
32 #define _FORCENAMELESSUNION
33 #include "wx/msw/private.h"
34 #include "wx/msw/ole/oleutils.h"
35 #include "wx/msw/ole/automtn.h"
38 #include "wx/msw/wince/time.h"
56 #include "wx/datetime.h"
57 #endif // wxUSE_DATETIME
59 static void ClearVariant(VARIANTARG
*pvarg
) ;
60 static void ReleaseVariant(VARIANTARG
*pvarg
) ;
61 // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr);
67 wxAutomationObject::wxAutomationObject(WXIDISPATCH
* dispatchPtr
)
69 m_dispatchPtr
= dispatchPtr
;
72 wxAutomationObject::~wxAutomationObject()
76 ((IDispatch
*)m_dispatchPtr
)->Release();
81 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
83 // For Put/Get, no named arguments are allowed.
84 bool wxAutomationObject::Invoke(const wxString
& member
, int action
,
85 wxVariant
& retValue
, int noArgs
, wxVariant args
[], const wxVariant
* ptrArgs
[]) const
90 // nonConstMember is necessary because the wxString class doesn't have enough consts...
91 wxString
nonConstMember(member
);
93 int ch
= nonConstMember
.Find('.');
96 // Use dot notation to get the next object
97 wxString
member2(nonConstMember
.Left((size_t) ch
));
98 wxString
rest(nonConstMember
.Right(nonConstMember
.length() - ch
- 1));
99 wxAutomationObject obj
;
100 if (!GetObject(obj
, member2
))
102 return obj
.Invoke(rest
, action
, retValue
, noArgs
, args
, ptrArgs
);
106 ClearVariant(& vReturn
);
108 VARIANTARG
* vReturnPtr
= & vReturn
;
110 // Find number of names args
111 int namedArgCount
= 0;
113 for (i
= 0; i
< noArgs
; i
++)
114 if (!INVOKEARG(i
).GetName().IsNull())
119 int namedArgStringCount
= namedArgCount
+ 1;
120 BSTR
* argNames
= new BSTR
[namedArgStringCount
];
121 argNames
[0] = wxConvertStringToOle(member
);
123 // Note that arguments are specified in reverse order
124 // (all totally logical; hey, we're dealing with OLE here.)
127 for (i
= 0; i
< namedArgCount
; i
++)
129 if (!INVOKEARG(i
).GetName().IsNull())
131 argNames
[(namedArgCount
-j
)] = wxConvertStringToOle(INVOKEARG(i
).GetName());
136 // + 1 for the member name, + 1 again in case we're a 'put'
137 DISPID
* dispIds
= new DISPID
[namedArgCount
+ 2];
140 DISPPARAMS dispparams
;
141 unsigned int uiArgErr
;
144 // Get the IDs for the member and its arguments. GetIDsOfNames expects the
145 // member name as the first name, followed by argument names (if any).
146 hr
= ((IDispatch
*)m_dispatchPtr
)->GetIDsOfNames(IID_NULL
, argNames
,
147 1 + namedArgCount
, LOCALE_SYSTEM_DEFAULT
, dispIds
);
150 // ShowException(szMember, hr, NULL, 0);
156 // if doing a property put(ref), we need to adjust the first argument to have a
157 // named arg of DISPID_PROPERTYPUT.
158 if (action
& (DISPATCH_PROPERTYPUT
| DISPATCH_PROPERTYPUTREF
))
161 dispIds
[1] = DISPID_PROPERTYPUT
;
162 vReturnPtr
= (VARIANTARG
*) NULL
;
165 // Convert the wxVariants to VARIANTARGs
166 VARIANTARG
* oleArgs
= new VARIANTARG
[noArgs
];
167 for (i
= 0; i
< noArgs
; i
++)
169 // Again, reverse args
170 if (!wxConvertVariantToOle(INVOKEARG((noArgs
-1) - i
), oleArgs
[i
]))
179 dispparams
.rgdispidNamedArgs
= dispIds
+ 1;
180 dispparams
.rgvarg
= oleArgs
;
181 dispparams
.cArgs
= noArgs
;
182 dispparams
.cNamedArgs
= namedArgCount
;
184 excep
.pfnDeferredFillIn
= NULL
;
186 hr
= ((IDispatch
*)m_dispatchPtr
)->Invoke(dispIds
[0], IID_NULL
, LOCALE_SYSTEM_DEFAULT
,
187 (WORD
)action
, &dispparams
, vReturnPtr
, &excep
, &uiArgErr
);
189 for (i
= 0; i
< namedArgStringCount
; i
++)
191 SysFreeString(argNames
[i
]);
196 for (i
= 0; i
< noArgs
; i
++)
197 ReleaseVariant(& oleArgs
[i
]) ;
202 // display the exception information if appropriate:
203 // ShowException((const char*) member, hr, &excep, uiArgErr);
205 // free exception structure information
206 SysFreeString(excep
.bstrSource
);
207 SysFreeString(excep
.bstrDescription
);
208 SysFreeString(excep
.bstrHelpFile
);
211 ReleaseVariant(vReturnPtr
);
218 // Convert result to wxVariant form
219 wxConvertOleToVariant(vReturn
, retValue
);
220 // Mustn't release the dispatch pointer
221 if (vReturn
.vt
== VT_DISPATCH
)
223 vReturn
.pdispVal
= (IDispatch
*) NULL
;
225 ReleaseVariant(& vReturn
);
231 // Invoke a member function
232 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
, int noArgs
, wxVariant args
[])
234 wxVariant retVariant
;
235 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, args
))
237 retVariant
.MakeNull();
242 wxVariant
wxAutomationObject::CallMethodArray(const wxString
& member
, int noArgs
, const wxVariant
**args
)
244 wxVariant retVariant
;
245 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, NULL
, args
))
247 retVariant
.MakeNull();
252 wxVariant
wxAutomationObject::CallMethod(const wxString
& member
,
253 const wxVariant
& arg1
, const wxVariant
& arg2
,
254 const wxVariant
& arg3
, const wxVariant
& arg4
,
255 const wxVariant
& arg5
, const wxVariant
& arg6
)
257 const wxVariant
** args
= new const wxVariant
*[6];
289 wxVariant retVariant
;
290 if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, i
, NULL
, args
))
292 retVariant
.MakeNull();
299 wxVariant
wxAutomationObject::GetPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
301 wxVariant retVariant
;
302 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
304 retVariant
.MakeNull();
308 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
310 wxVariant retVariant
;
311 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
313 retVariant
.MakeNull();
318 wxVariant
wxAutomationObject::GetProperty(const wxString
& property
,
319 const wxVariant
& arg1
, const wxVariant
& arg2
,
320 const wxVariant
& arg3
, const wxVariant
& arg4
,
321 const wxVariant
& arg5
, const wxVariant
& arg6
)
323 const wxVariant
** args
= new const wxVariant
*[6];
355 wxVariant retVariant
;
356 if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, i
, NULL
, args
))
358 retVariant
.MakeNull();
364 bool wxAutomationObject::PutProperty(const wxString
& property
, int noArgs
, wxVariant args
[])
366 wxVariant retVariant
;
367 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, args
))
374 bool wxAutomationObject::PutPropertyArray(const wxString
& property
, int noArgs
, const wxVariant
**args
)
376 wxVariant retVariant
;
377 if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, NULL
, args
))
384 bool wxAutomationObject::PutProperty(const wxString
& property
,
385 const wxVariant
& arg1
, const wxVariant
& arg2
,
386 const wxVariant
& arg3
, const wxVariant
& arg4
,
387 const wxVariant
& arg5
, const wxVariant
& arg6
)
389 const wxVariant
** args
= new const wxVariant
*[6];
421 wxVariant retVariant
;
422 bool ret
= Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, i
, NULL
, args
);
428 // Uses DISPATCH_PROPERTYGET
429 // and returns a dispatch pointer. The calling code should call Release
430 // on the pointer, though this could be implicit by constructing an wxAutomationObject
431 // with it and letting the destructor call Release.
432 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const
434 wxVariant retVariant
;
435 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
))
437 if (retVariant
.GetType() == wxT("void*"))
439 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
443 return (WXIDISPATCH
*) NULL
;
446 // Uses DISPATCH_PROPERTYGET
447 // and returns a dispatch pointer. The calling code should call Release
448 // on the pointer, though this could be implicit by constructing an wxAutomationObject
449 // with it and letting the destructor call Release.
450 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, const wxVariant
**args
) const
452 wxVariant retVariant
;
453 if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
))
455 if (retVariant
.GetType() == wxT("void*"))
457 return (WXIDISPATCH
*) retVariant
.GetVoidPtr();
461 return (WXIDISPATCH
*) NULL
;
465 // A way of initialising another wxAutomationObject with a dispatch object
466 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, wxVariant args
[]) const
468 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
471 obj
.SetDispatchPtr(dispatch
);
478 // A way of initialising another wxAutomationObject with a dispatch object
479 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, const wxVariant
**args
) const
481 WXIDISPATCH
* dispatch
= GetDispatchProperty(property
, noArgs
, args
);
484 obj
.SetDispatchPtr(dispatch
);
491 // Get a dispatch pointer from the current object associated
493 bool wxAutomationObject::GetInstance(const wxString
& classId
) const
499 IUnknown
* pUnk
= NULL
;
501 wxBasicString
unicodeName(classId
);
503 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
505 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
509 if (FAILED(GetActiveObject(clsId
, NULL
, &pUnk
)))
511 wxLogWarning(wxT("Cannot find an active object"));
515 if (pUnk
->QueryInterface(IID_IDispatch
, (LPVOID
*) &m_dispatchPtr
) != S_OK
)
517 wxLogWarning(wxT("Cannot find IDispatch interface"));
524 // Get a dispatch pointer from a new object associated
525 // with the given class id
526 bool wxAutomationObject::CreateInstance(const wxString
& classId
) const
533 wxBasicString
unicodeName(classId
);
535 if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
)))
537 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
541 // get the server IDispatch interface
543 // NB: using CLSCTX_INPROC_HANDLER results in failure when getting
544 // Automation interface for Microsoft Office applications so don't use
545 // CLSCTX_ALL which includes it
546 if (FAILED(CoCreateInstance(clsId
, NULL
, CLSCTX_SERVER
, IID_IDispatch
,
547 (void**)&m_dispatchPtr
)))
549 wxLogWarning(wxT("Cannot start an instance of this class."));
557 WXDLLEXPORT
bool wxConvertVariantToOle(const wxVariant
& variant
, VARIANTARG
& oleVariant
)
559 ClearVariant(&oleVariant
);
560 if (variant
.IsNull())
562 oleVariant
.vt
= VT_NULL
;
566 wxString
type(variant
.GetType());
569 if (type
== wxT("long"))
571 oleVariant
.vt
= VT_I4
;
572 oleVariant
.lVal
= variant
.GetLong() ;
574 // cVal not always present
576 else if (type
== wxT("char"))
578 oleVariant
.vt
=VT_I1
; // Signed Char
579 oleVariant
.cVal
=variant
.GetChar();
582 else if (type
== wxT("double"))
584 oleVariant
.vt
= VT_R8
;
585 oleVariant
.dblVal
= variant
.GetDouble();
587 else if (type
== wxT("bool"))
589 oleVariant
.vt
= VT_BOOL
;
590 // 'bool' required for VC++ 4 apparently
591 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000))
592 oleVariant
.bool = variant
.GetBool();
594 oleVariant
.boolVal
= variant
.GetBool();
597 else if (type
== wxT("string"))
599 wxString
str( variant
.GetString() );
600 oleVariant
.vt
= VT_BSTR
;
601 oleVariant
.bstrVal
= wxConvertStringToOle(str
);
604 else if (type
== wxT("datetime"))
606 wxDateTime
date( variant
.GetDateTime() );
607 oleVariant
.vt
= VT_DATE
;
609 long dosDateTime
= date
.GetAsDOS();
610 short dosDate
= short((dosDateTime
& 0xFFFF0000) >> 16);
611 short dosTime
= short(dosDateTime
& 0xFFFF);
613 DosDateTimeToVariantTime(dosDate
, dosTime
, & oleVariant
.date
);
616 else if (type
== wxT("void*"))
618 oleVariant
.vt
= VT_DISPATCH
;
619 oleVariant
.pdispVal
= (IDispatch
*) variant
.GetVoidPtr();
621 else if (type
== wxT("list") || type
== wxT("stringlist"))
623 oleVariant
.vt
= VT_VARIANT
| VT_ARRAY
;
626 SAFEARRAYBOUND saBound
;
627 VARIANTARG
*pvargBase
;
631 int iCount
= variant
.GetCount();
634 saBound
.cElements
= iCount
;
636 psa
= SafeArrayCreate(VT_VARIANT
, 1, &saBound
);
640 SafeArrayAccessData(psa
, (void**)&pvargBase
);
643 for (i
= 0; i
< iCount
; i
++)
645 // copy each string in the list of strings
646 wxVariant
eachVariant(variant
[i
]);
647 if (!wxConvertVariantToOle(eachVariant
, * pvarg
))
649 // memory failure: back out and free strings alloc'ed up to
650 // now, and then the array itself.
652 for (j
= 0; j
< i
; j
++)
654 SysFreeString(pvarg
->bstrVal
);
657 SafeArrayDestroy(psa
);
663 SafeArrayUnaccessData(psa
);
665 oleVariant
.parray
= psa
;
669 oleVariant
.vt
= VT_NULL
;
676 #define VT_TYPEMASK 0xfff
680 wxConvertOleToVariant(const VARIANTARG
& oleVariant
, wxVariant
& variant
)
683 if ( oleVariant
.vt
& VT_ARRAY
)
686 // Compute the total number of elements in all array dimensions
688 for ( int cDims
= 0; cDims
< oleVariant
.parray
->cDims
; cDims
++ )
689 cElements
*= oleVariant
.parray
->rgsabound
[cDims
].cElements
;
691 // Get a pointer to the data
693 HRESULT hr
= SafeArrayAccessData(oleVariant
.parray
, &pvdata
);
697 switch (oleVariant
.vt
& VT_TYPEMASK
)
702 VARIANTARG
*variant_data
=(VARIANTARG
*)pvdata
;
703 for ( int i
= 0; i
< cElements
; i
++ )
705 VARIANTARG
& oleElement
= variant_data
[i
];
707 if ( !wxConvertOleToVariant(oleElement
, vElement
) )
714 variant
.Append(vElement
);
721 wxArrayString strings
;
722 BSTR
*string_val
=(BSTR
*)pvdata
;
723 for ( int i
= 0; i
< cElements
; ++i
)
725 wxString str
=wxConvertStringFromOle(*string_val
);
734 wxLogDebug(_T("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
735 oleVariant
.vt
& VT_TYPEMASK
);
736 variant
= wxVariant();
741 SafeArrayUnaccessData(oleVariant
.parray
);
743 else if ( oleVariant
.vt
& VT_BYREF
)
745 switch ( oleVariant
.vt
& VT_TYPEMASK
)
749 VARIANTARG
& oleReference
= *((LPVARIANT
)oleVariant
.byref
);
750 if (!wxConvertOleToVariant(oleReference
,variant
))
756 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),
761 else // simply type (not array or reference)
763 switch ( oleVariant
.vt
& VT_TYPEMASK
)
767 wxString
str(wxConvertStringFromOle(oleVariant
.bstrVal
));
775 unsigned short dosDate
= 0;
776 unsigned short dosTime
= 0;
777 VariantTimeToDosDateTime(oleVariant
.date
, & dosDate
, & dosTime
);
779 long dosDateTime
= (dosDate
<< 16) | dosTime
;
781 date
.SetFromDOS(dosDateTime
);
784 #endif // wxUSE_DATETIME
788 variant
= (long) oleVariant
.lVal
;
792 variant
= (long) oleVariant
.iVal
;
796 variant
= oleVariant
.boolVal
!= 0;
800 variant
= oleVariant
.dblVal
;
804 variant
= (void*) oleVariant
.pdispVal
;
812 break; // Ignore Empty Variant, used only during destruction of objects
815 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),
816 oleVariant
.vt
,oleVariant
.vt
&VT_TYPEMASK
);
827 * Zeros a variant structure without regard to current contents
829 static void ClearVariant(VARIANTARG
*pvarg
)
831 pvarg
->vt
= VT_EMPTY
;
832 pvarg
->wReserved1
= 0;
833 pvarg
->wReserved2
= 0;
834 pvarg
->wReserved3
= 0;
841 * Clears a particular variant structure and releases any external objects
842 * or memory contained in the variant. Supports the data types listed above.
844 static void ReleaseVariant(VARIANTARG
*pvarg
)
847 VARIANTARG _huge
*pvargArray
;
848 LONG lLBound
, lUBound
, l
;
850 vt
= (VARTYPE
)(pvarg
->vt
& 0xfff); // mask off flags
852 // check if an array. If so, free its contents, then the array itself.
853 if (V_ISARRAY(pvarg
))
855 // variant arrays are all this routine currently knows about. Since a
856 // variant can contain anything (even other arrays), call ourselves
858 if (vt
== VT_VARIANT
)
860 SafeArrayGetLBound(pvarg
->parray
, 1, &lLBound
);
861 SafeArrayGetUBound(pvarg
->parray
, 1, &lUBound
);
863 if (lUBound
> lLBound
)
867 SafeArrayAccessData(pvarg
->parray
, (void**)&pvargArray
);
869 for (l
= 0; l
< lUBound
; l
++)
871 ReleaseVariant(pvargArray
);
875 SafeArrayUnaccessData(pvarg
->parray
);
880 wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type"));
883 // Free the array itself.
884 SafeArrayDestroy(pvarg
->parray
);
892 pvarg
->pdispVal
->Release();
896 SysFreeString(pvarg
->bstrVal
);
903 case VT_ERROR
: // to avoid erroring on an error return from Excel
906 // no work for these types
910 wxLogWarning(wxT("ReleaseVariant: Unknown type"));
920 void ShowException(LPOLESTR szMember
, HRESULT hr
, EXCEPINFO
*pexcep
, unsigned int uiArgErr
)
924 switch (GetScode(hr
))
926 case DISP_E_UNKNOWNNAME
:
927 wsprintf(szBuf
, L
"%s: Unknown name or named argument.", szMember
);
930 case DISP_E_BADPARAMCOUNT
:
931 wsprintf(szBuf
, L
"%s: Incorrect number of arguments.", szMember
);
934 case DISP_E_EXCEPTION
:
935 wsprintf(szBuf
, L
"%s: Error %d: ", szMember
, pexcep
->wCode
);
936 if (pexcep
->bstrDescription
!= NULL
)
937 lstrcat(szBuf
, pexcep
->bstrDescription
);
939 lstrcat(szBuf
, L
"<<No Description>>");
942 case DISP_E_MEMBERNOTFOUND
:
943 wsprintf(szBuf
, L
"%s: method or property not found.", szMember
);
946 case DISP_E_OVERFLOW
:
947 wsprintf(szBuf
, L
"%s: Overflow while coercing argument values.", szMember
);
950 case DISP_E_NONAMEDARGS
:
951 wsprintf(szBuf
, L
"%s: Object implementation does not support named arguments.",
955 case DISP_E_UNKNOWNLCID
:
956 wsprintf(szBuf
, L
"%s: The locale ID is unknown.", szMember
);
959 case DISP_E_PARAMNOTOPTIONAL
:
960 wsprintf(szBuf
, L
"%s: Missing a required parameter.", szMember
);
963 case DISP_E_PARAMNOTFOUND
:
964 wsprintf(szBuf
, L
"%s: Argument not found, argument %d.", szMember
, uiArgErr
);
967 case DISP_E_TYPEMISMATCH
:
968 wsprintf(szBuf
, L
"%s: Type mismatch, argument %d.", szMember
, uiArgErr
);
972 wsprintf(szBuf
, L
"%s: Unknown error occurred.", szMember
);
981 #endif // wxUSE_OLE_AUTOMATION