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 
  30 #define _FORCENAMELESSUNION 
  31 #include "wx/msw/private.h" 
  32 #include "wx/msw/ole/oleutils.h" 
  33 #include "wx/msw/ole/automtn.h" 
  36 #include "wx/msw/wince/time.h" 
  54 #include "wx/datetime.h" 
  55 #endif // wxUSE_DATETIME 
  57 #if wxUSE_OLE_AUTOMATION 
  59 #include <wx/vector.h> 
  61 // Report an OLE error when calling the specified method to the user via wxLog. 
  63 ShowException(const wxString
& member
, 
  65               EXCEPINFO 
*pexcep 
= NULL
, 
  66               unsigned int uiArgErr 
= 0); 
  70 wxAutomationObject::wxAutomationObject(WXIDISPATCH
* dispatchPtr
) 
  72     m_dispatchPtr 
= dispatchPtr
; 
  73     m_lcid 
= LOCALE_SYSTEM_DEFAULT
; 
  76 wxAutomationObject::~wxAutomationObject() 
  80         ((IDispatch
*)m_dispatchPtr
)->Release(); 
  88 // A simple helper that ensures that VARIANT is destroyed on scope exit. 
  89 struct wxOleVariantArg 
: VARIANTARG
 
  91     wxOleVariantArg()  { VariantInit(this);  } 
  92     ~wxOleVariantArg() { VariantClear(this); } 
  95 } // anonymous namespace 
  98 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i])) 
 100 // For Put/Get, no named arguments are allowed. 
 101 // WARNING: if args contain IDispatches, their reference count will be decreased 
 102 // by one after Invoke() returns! 
 103 bool wxAutomationObject::Invoke(const wxString
& member
, int action
, 
 104         wxVariant
& retValue
, int noArgs
, wxVariant args
[], const wxVariant
* ptrArgs
[]) const 
 109     int ch 
= member
.Find('.'); 
 112         // Use dot notation to get the next object 
 113         wxString 
member2(member
.Left((size_t) ch
)); 
 114         wxString 
rest(member
.Right(member
.length() - ch 
- 1)); 
 115         wxAutomationObject obj
; 
 116         if (!GetObject(obj
, member2
)) 
 118         return obj
.Invoke(rest
, action
, retValue
, noArgs
, args
, ptrArgs
); 
 121     wxOleVariantArg vReturn
; 
 122     wxOleVariantArg
* vReturnPtr 
= & vReturn
; 
 124     // Find number of names args 
 125     int namedArgCount 
= 0; 
 127     for (i 
= 0; i 
< noArgs
; i
++) 
 129         if ( !INVOKEARG(i
).GetName().empty() ) 
 135     int namedArgStringCount 
= namedArgCount 
+ 1; 
 136     wxVector
<wxBasicString
> argNames(namedArgStringCount
, wxString()); 
 137     argNames
[0] = member
; 
 139     // Note that arguments are specified in reverse order 
 140     // (all totally logical; hey, we're dealing with OLE here.) 
 143     for (i 
= 0; i 
< namedArgCount
; i
++) 
 145         if ( !INVOKEARG(i
).GetName().empty() ) 
 147             argNames
[(namedArgCount
-j
)] = INVOKEARG(i
).GetName(); 
 152     // + 1 for the member name, + 1 again in case we're a 'put' 
 153     wxVector
<DISPID
> dispIds(namedArgCount 
+ 2); 
 156     DISPPARAMS dispparams
; 
 157     unsigned int uiArgErr
; 
 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
, 
 162                                 // We rely on the fact that wxBasicString is 
 163                                 // just BSTR with some methods here. 
 164                                 reinterpret_cast<BSTR 
*>(&argNames
[0]), 
 165                                 1 + namedArgCount
, m_lcid
, &dispIds
[0]); 
 168         ShowException(member
, hr
); 
 172     // if doing a property put(ref), we need to adjust the first argument to have a 
 173     // named arg of DISPID_PROPERTYPUT. 
 174     if (action 
& (DISPATCH_PROPERTYPUT 
| DISPATCH_PROPERTYPUTREF
)) 
 177         dispIds
[1] = DISPID_PROPERTYPUT
; 
 181     // Convert the wxVariants to VARIANTARGs 
 182     wxVector
<wxOleVariantArg
> oleArgs(noArgs
); 
 183     for (i 
= 0; i 
< noArgs
; i
++) 
 185         // Again, reverse args 
 186         if (!wxConvertVariantToOle(INVOKEARG((noArgs
-1) - i
), oleArgs
[i
])) 
 190     dispparams
.rgdispidNamedArgs 
= &dispIds
[0] + 1; 
 191     dispparams
.rgvarg 
= oleArgs
.empty() ? NULL 
: &oleArgs
[0]; 
 192     dispparams
.cArgs 
= noArgs
; 
 193     dispparams
.cNamedArgs 
= namedArgCount
; 
 198     hr 
= ((IDispatch
*)m_dispatchPtr
)->Invoke(dispIds
[0], IID_NULL
, m_lcid
, 
 199                         (WORD
)action
, &dispparams
, vReturnPtr
, &excep
, &uiArgErr
); 
 203         // display the exception information if appropriate: 
 204         ShowException(member
, hr
, &excep
, uiArgErr
); 
 206         // free exception structure information 
 207         SysFreeString(excep
.bstrSource
); 
 208         SysFreeString(excep
.bstrDescription
); 
 209         SysFreeString(excep
.bstrHelpFile
); 
 217             // Convert result to wxVariant form 
 218             if (!wxConvertOleToVariant(vReturn
, retValue
)) 
 220             // Mustn't release the dispatch pointer 
 221             if (vReturn
.vt 
== VT_DISPATCH
) 
 223                 vReturn
.pdispVal 
= NULL
; 
 225             // Mustn't free the SAFEARRAY if it is contained in the retValue 
 226             if ((vReturn
.vt 
& VT_ARRAY
) && 
 227                     retValue
.GetType() == wxS("safearray")) 
 229                 vReturn
.parray 
= NULL
; 
 236 // Invoke a member function 
 237 wxVariant 
wxAutomationObject::CallMethod(const wxString
& member
, int noArgs
, wxVariant args
[]) 
 239     wxVariant retVariant
; 
 240     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, args
)) 
 242         retVariant
.MakeNull(); 
 247 wxVariant 
wxAutomationObject::CallMethodArray(const wxString
& member
, int noArgs
, const wxVariant 
**args
) 
 249     wxVariant retVariant
; 
 250     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, NULL
, args
)) 
 252         retVariant
.MakeNull(); 
 257 wxVariant 
wxAutomationObject::CallMethod(const wxString
& member
, 
 258         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 259         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 260         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 262     const wxVariant
** args 
= new const wxVariant
*[6]; 
 294     wxVariant retVariant
; 
 295     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, i
, NULL
, args
)) 
 297         retVariant
.MakeNull(); 
 304 wxVariant 
wxAutomationObject::GetPropertyArray(const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 306     wxVariant retVariant
; 
 307     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
)) 
 309         retVariant
.MakeNull(); 
 313 wxVariant 
wxAutomationObject::GetProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 315     wxVariant retVariant
; 
 316     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
)) 
 318         retVariant
.MakeNull(); 
 323 wxVariant 
wxAutomationObject::GetProperty(const wxString
& property
, 
 324         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 325         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 326         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 328     const wxVariant
** args 
= new const wxVariant
*[6]; 
 360     wxVariant retVariant
; 
 361     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, i
, NULL
, args
)) 
 363         retVariant
.MakeNull(); 
 369 bool wxAutomationObject::PutProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) 
 371     wxVariant retVariant
; 
 372     if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, args
)) 
 379 bool wxAutomationObject::PutPropertyArray(const wxString
& property
, int noArgs
, const wxVariant 
**args
) 
 381     wxVariant retVariant
; 
 382     if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, NULL
, args
)) 
 389 bool wxAutomationObject::PutProperty(const wxString
& property
, 
 390         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 391         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 392         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 394     const wxVariant
** args 
= new const wxVariant
*[6]; 
 426     wxVariant retVariant
; 
 427     bool ret 
= Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, i
, NULL
, args
); 
 433 // Uses DISPATCH_PROPERTYGET 
 434 // and returns a dispatch pointer. The calling code should call Release 
 435 // on the pointer, though this could be implicit by constructing an wxAutomationObject 
 436 // with it and letting the destructor call Release. 
 437 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 439     wxVariant retVariant
; 
 440     if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
)) 
 442         if (retVariant
.GetType() == wxT("void*")) 
 444             return (WXIDISPATCH
*) retVariant
.GetVoidPtr(); 
 451 // Uses DISPATCH_PROPERTYGET 
 452 // and returns a dispatch pointer. The calling code should call Release 
 453 // on the pointer, though this could be implicit by constructing an wxAutomationObject 
 454 // with it and letting the destructor call Release. 
 455 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 457     wxVariant retVariant
; 
 458     if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
)) 
 460         if (retVariant
.GetType() == wxT("void*")) 
 462             return (WXIDISPATCH
*) retVariant
.GetVoidPtr(); 
 470 // A way of initialising another wxAutomationObject with a dispatch object 
 471 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 473     WXIDISPATCH
* dispatch 
= GetDispatchProperty(property
, noArgs
, args
); 
 476         obj
.SetDispatchPtr(dispatch
); 
 477         obj
.SetLCID(GetLCID()); 
 484 // A way of initialising another wxAutomationObject with a dispatch object 
 485 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 487     WXIDISPATCH
* dispatch 
= GetDispatchProperty(property
, noArgs
, args
); 
 490         obj
.SetDispatchPtr(dispatch
); 
 491         obj
.SetLCID(GetLCID()); 
 501 HRESULT 
wxCLSIDFromProgID(const wxString
& progId
, CLSID
& clsId
) 
 503     HRESULT hr 
= CLSIDFromProgID(wxBasicString(progId
), &clsId
); 
 506         wxLogSysError(hr
, _("Failed to find CLSID of \"%s\""), progId
); 
 511 void *DoCreateInstance(const wxString
& progId
, const CLSID
& clsId
) 
 513     // get the server IDispatch interface 
 515     // NB: using CLSCTX_INPROC_HANDLER results in failure when getting 
 516     //     Automation interface for Microsoft Office applications so don't use 
 517     //     CLSCTX_ALL which includes it 
 518     void *pDispatch 
= NULL
; 
 519     HRESULT hr 
= CoCreateInstance(clsId
, NULL
, CLSCTX_SERVER
, 
 520                                   IID_IDispatch
, &pDispatch
); 
 523         wxLogSysError(hr
, _("Failed to create an instance of \"%s\""), progId
); 
 530 } // anonymous namespace 
 532 // Get a dispatch pointer from the current object associated 
 534 bool wxAutomationObject::GetInstance(const wxString
& progId
, int flags
) const 
 540     HRESULT hr 
= wxCLSIDFromProgID(progId
, clsId
); 
 544     IUnknown 
*pUnk 
= NULL
; 
 545     hr 
= GetActiveObject(clsId
, NULL
, &pUnk
); 
 548         if ( flags 
& wxAutomationInstance_CreateIfNeeded 
) 
 550             const_cast<wxAutomationObject 
*>(this)-> 
 551                 m_dispatchPtr 
= DoCreateInstance(progId
, clsId
); 
 557             // Log an error except if we're supposed to fail silently when the 
 558             // error is that no current instance exists. 
 559             if ( hr 
!= MK_E_UNAVAILABLE 
|| 
 560                     !(flags 
& wxAutomationInstance_SilentIfNone
) ) 
 563                               _("Cannot get an active instance of \"%s\""), 
 571     hr 
= pUnk
->QueryInterface(IID_IDispatch
, (LPVOID
*) &m_dispatchPtr
); 
 575                       _("Failed to get OLE automation interface for \"%s\""), 
 583 // Get a dispatch pointer from a new object associated 
 584 // with the given ProgID 
 585 bool wxAutomationObject::CreateInstance(const wxString
& progId
) const 
 591     HRESULT hr 
= wxCLSIDFromProgID(progId
, clsId
); 
 595     const_cast<wxAutomationObject 
*>(this)-> 
 596         m_dispatchPtr 
= DoCreateInstance(progId
, clsId
); 
 598     return m_dispatchPtr 
!= NULL
; 
 601 LCID 
wxAutomationObject::GetLCID() const 
 606 void wxAutomationObject::SetLCID(LCID lcid
) 
 612 ShowException(const wxString
& member
, 
 615               unsigned int uiArgErr
) 
 618     switch (GetScode(hr
)) 
 620         case DISP_E_UNKNOWNNAME
: 
 621             message 
= _("Unknown name or named argument."); 
 624         case DISP_E_BADPARAMCOUNT
: 
 625             message 
= _("Incorrect number of arguments."); 
 628         case DISP_E_EXCEPTION
: 
 631                 if ( pexcep
->bstrDescription 
) 
 632                     message 
<< pexcep
->bstrDescription 
<< wxS(" "); 
 633                 message 
+= wxString::Format(wxS("error code %u"), pexcep
->wCode
); 
 637                 message 
= _("Unknown exception"); 
 641         case DISP_E_MEMBERNOTFOUND
: 
 642             message 
= _("Method or property not found."); 
 645         case DISP_E_OVERFLOW
: 
 646             message 
= _("Overflow while coercing argument values."); 
 649         case DISP_E_NONAMEDARGS
: 
 650             message 
= _("Object implementation does not support named arguments."); 
 653         case DISP_E_UNKNOWNLCID
: 
 654             message 
= _("The locale ID is unknown."); 
 657         case DISP_E_PARAMNOTOPTIONAL
: 
 658             message 
= _("Missing a required parameter."); 
 661         case DISP_E_PARAMNOTFOUND
: 
 662             message
.Printf(_("Argument %u not found."), uiArgErr
); 
 665         case DISP_E_TYPEMISMATCH
: 
 666             message
.Printf(_("Type mismatch in argument %u."), uiArgErr
); 
 669         case ERROR_FILE_NOT_FOUND
: 
 670             message 
= _("The system cannot find the file specified."); 
 673         case REGDB_E_CLASSNOTREG
: 
 674             message 
= _("Class not registered."); 
 678             message
.Printf(_("Unknown error %08x"), hr
); 
 682     wxLogError(_("OLE Automation error in %s: %s"), member
, message
); 
 685 #endif // wxUSE_OLE_AUTOMATION