]>
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     // start a new copy of Excel, grab the IDispatch interface 
 542     if (FAILED(CoCreateInstance(clsId
, NULL
, CLSCTX_LOCAL_SERVER
, IID_IDispatch
, (void**)&m_dispatchPtr
))) 
 544         wxLogWarning(wxT("Cannot start an instance of this class.")); 
 552 WXDLLEXPORT 
bool wxConvertVariantToOle(const wxVariant
& variant
, VARIANTARG
& oleVariant
) 
 554     ClearVariant(&oleVariant
); 
 555     if (variant
.IsNull()) 
 557         oleVariant
.vt 
= VT_NULL
; 
 561     wxString 
type(variant
.GetType()); 
 564     if (type 
== wxT("long")) 
 566         oleVariant
.vt 
= VT_I4
; 
 567         oleVariant
.lVal 
= variant
.GetLong() ; 
 569     // cVal not always present 
 571     else if (type 
== wxT("char")) 
 573         oleVariant
.vt
=VT_I1
;            // Signed Char 
 574         oleVariant
.cVal
=variant
.GetChar(); 
 577     else if (type 
== wxT("double")) 
 579         oleVariant
.vt 
= VT_R8
; 
 580         oleVariant
.dblVal 
= variant
.GetDouble(); 
 582     else if (type 
== wxT("bool")) 
 584         oleVariant
.vt 
= VT_BOOL
; 
 585         // 'bool' required for VC++ 4 apparently 
 586 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000)) 
 587         oleVariant
.bool = variant
.GetBool(); 
 589         oleVariant
.boolVal 
= variant
.GetBool(); 
 592     else if (type 
== wxT("string")) 
 594         wxString 
str( variant
.GetString() ); 
 595         oleVariant
.vt 
= VT_BSTR
; 
 596         oleVariant
.bstrVal 
= wxConvertStringToOle(str
); 
 599     else if (type 
== wxT("datetime")) 
 601         wxDateTime 
date( variant
.GetDateTime() ); 
 602         oleVariant
.vt 
= VT_DATE
; 
 604         long dosDateTime 
= date
.GetAsDOS(); 
 605         short dosDate 
= short((dosDateTime 
& 0xFFFF0000) >> 16); 
 606         short dosTime 
= short(dosDateTime 
& 0xFFFF); 
 608         DosDateTimeToVariantTime(dosDate
, dosTime
, & oleVariant
.date
); 
 611     else if (type 
== wxT("void*")) 
 613         oleVariant
.vt 
= VT_DISPATCH
; 
 614         oleVariant
.pdispVal 
= (IDispatch
*) variant
.GetVoidPtr(); 
 616     else if (type 
== wxT("list") || type 
== wxT("stringlist")) 
 618         oleVariant
.vt 
= VT_VARIANT 
| VT_ARRAY
; 
 621         SAFEARRAYBOUND saBound
; 
 622         VARIANTARG 
*pvargBase
; 
 626         int iCount 
= variant
.GetCount(); 
 629         saBound
.cElements 
= iCount
; 
 631         psa 
= SafeArrayCreate(VT_VARIANT
, 1, &saBound
); 
 635         SafeArrayAccessData(psa
, (void**)&pvargBase
); 
 638         for (i 
= 0; i 
< iCount
; i
++) 
 640             // copy each string in the list of strings 
 641             wxVariant 
eachVariant(variant
[i
]); 
 642             if (!wxConvertVariantToOle(eachVariant
, * pvarg
)) 
 644                 // memory failure:  back out and free strings alloc'ed up to 
 645                 // now, and then the array itself. 
 647                 for (j 
= 0; j 
< i
; j
++) 
 649                     SysFreeString(pvarg
->bstrVal
); 
 652                 SafeArrayDestroy(psa
); 
 658         SafeArrayUnaccessData(psa
); 
 660         oleVariant
.parray 
= psa
; 
 664         oleVariant
.vt 
= VT_NULL
; 
 671 #define VT_TYPEMASK 0xfff 
 675 wxConvertOleToVariant(const VARIANTARG
& oleVariant
, wxVariant
& variant
) 
 677     if ( oleVariant
.vt 
& VT_ARRAY 
) 
 681         // Compute the total number of elements in all array dimensions 
 683         for ( int cDims 
= 0; cDims 
< oleVariant
.parray
->cDims
; cDims
++ ) 
 684             cElements 
*= oleVariant
.parray
->rgsabound
[cDims
].cElements
; 
 686         // Get a pointer to the data 
 688         HRESULT hr 
= SafeArrayAccessData(oleVariant
.parray
, (void **)&pvdata
); 
 693         for ( int i 
= 0; i 
< cElements
; i
++ ) 
 695             VARIANTARG
& oleElement 
= pvdata
[i
]; 
 697             if ( !wxConvertOleToVariant(oleElement
, vElement
) ) 
 704             variant
.Append(vElement
); 
 707         SafeArrayUnaccessData(oleVariant
.parray
); 
 709     else if ( oleVariant
.vt 
& VT_BYREF 
) 
 711         switch ( oleVariant
.vt 
& VT_TYPEMASK 
) 
 715                     VARIANTARG
& oleReference 
= *((LPVARIANT
)oleVariant
.byref
); 
 716                     if (!wxConvertOleToVariant(oleReference
,variant
)) 
 722                 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),oleVariant
.vt
); 
 726     else // simply type (not array or reference) 
 728         switch (oleVariant
.vt 
& VT_TYPEMASK
) 
 732                     wxString 
str(wxConvertStringFromOle(oleVariant
.bstrVal
)); 
 739                     unsigned short dosDate 
= 0; 
 740                     unsigned short dosTime 
= 0; 
 741                     VariantTimeToDosDateTime(oleVariant
.date
, & dosDate
, & dosTime
); 
 743                     long dosDateTime 
= (dosDate 
<< 16) | dosTime
; 
 745                     date
.SetFromDOS(dosDateTime
); 
 752                     variant 
= (long) oleVariant
.lVal
; 
 757                     variant 
= (long) oleVariant
.iVal
; 
 763 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC 
 764 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type 
 765                     variant 
= (long) (oleVariant
.bool != 0); 
 767                     variant 
= (bool) (oleVariant
.bool != 0); 
 770 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type 
 771                     variant 
= (long) (oleVariant
.boolVal 
!= 0); 
 773                     variant 
= (bool) (oleVariant
.boolVal 
!= 0); 
 780                     variant 
= oleVariant
.dblVal
; 
 785                     variant 
= (void*) oleVariant
.pdispVal
; 
 795                     break;    // Ignore Empty Variant, used only during destruction of objects 
 799                     wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),oleVariant
.vt
,oleVariant
.vt
&VT_TYPEMASK
); 
 811  *  Zeros a variant structure without regard to current contents 
 813 static void ClearVariant(VARIANTARG 
*pvarg
) 
 815     pvarg
->vt 
= VT_EMPTY
; 
 816     pvarg
->wReserved1 
= 0; 
 817     pvarg
->wReserved2 
= 0; 
 818     pvarg
->wReserved3 
= 0; 
 825  *  Clears a particular variant structure and releases any external objects 
 826  *  or memory contained in the variant.  Supports the data types listed above. 
 828 static void ReleaseVariant(VARIANTARG 
*pvarg
) 
 831     VARIANTARG _huge 
*pvargArray
; 
 832     LONG lLBound
, lUBound
, l
; 
 834     vt 
= (VARTYPE
)(pvarg
->vt 
& 0xfff);        // mask off flags 
 836     // check if an array.  If so, free its contents, then the array itself. 
 837     if (V_ISARRAY(pvarg
)) 
 839         // variant arrays are all this routine currently knows about.  Since a 
 840         // variant can contain anything (even other arrays), call ourselves 
 842         if (vt 
== VT_VARIANT
) 
 844             SafeArrayGetLBound(pvarg
->parray
, 1, &lLBound
); 
 845             SafeArrayGetUBound(pvarg
->parray
, 1, &lUBound
); 
 847             if (lUBound 
> lLBound
) 
 851                 SafeArrayAccessData(pvarg
->parray
, (void**)&pvargArray
); 
 853                 for (l 
= 0; l 
< lUBound
; l
++) 
 855                     ReleaseVariant(pvargArray
); 
 859                 SafeArrayUnaccessData(pvarg
->parray
); 
 864             wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type")); 
 867         // Free the array itself. 
 868         SafeArrayDestroy(pvarg
->parray
); 
 876                     pvarg
->pdispVal
->Release(); 
 880                 SysFreeString(pvarg
->bstrVal
); 
 887             case VT_ERROR
:        // to avoid erroring on an error return from Excel 
 889                 // no work for these types 
 893                 wxLogWarning(wxT("ReleaseVariant: Unknown type")); 
 903 void ShowException(LPOLESTR szMember
, HRESULT hr
, EXCEPINFO 
*pexcep
, unsigned int uiArgErr
) 
 907     switch (GetScode(hr
)) 
 909         case DISP_E_UNKNOWNNAME
: 
 910             wsprintf(szBuf
, L
"%s: Unknown name or named argument.", szMember
); 
 913         case DISP_E_BADPARAMCOUNT
: 
 914             wsprintf(szBuf
, L
"%s: Incorrect number of arguments.", szMember
); 
 917         case DISP_E_EXCEPTION
: 
 918             wsprintf(szBuf
, L
"%s: Error %d: ", szMember
, pexcep
->wCode
); 
 919             if (pexcep
->bstrDescription 
!= NULL
) 
 920                 lstrcat(szBuf
, pexcep
->bstrDescription
); 
 922                 lstrcat(szBuf
, L
"<<No Description>>"); 
 925         case DISP_E_MEMBERNOTFOUND
: 
 926             wsprintf(szBuf
, L
"%s: method or property not found.", szMember
); 
 929         case DISP_E_OVERFLOW
: 
 930             wsprintf(szBuf
, L
"%s: Overflow while coercing argument values.", szMember
); 
 933         case DISP_E_NONAMEDARGS
: 
 934             wsprintf(szBuf
, L
"%s: Object implementation does not support named arguments.", 
 938         case DISP_E_UNKNOWNLCID
: 
 939             wsprintf(szBuf
, L
"%s: The locale ID is unknown.", szMember
); 
 942         case DISP_E_PARAMNOTOPTIONAL
: 
 943             wsprintf(szBuf
, L
"%s: Missing a required parameter.", szMember
); 
 946         case DISP_E_PARAMNOTFOUND
: 
 947             wsprintf(szBuf
, L
"%s: Argument not found, argument %d.", szMember
, uiArgErr
); 
 950         case DISP_E_TYPEMISMATCH
: 
 951             wsprintf(szBuf
, L
"%s: Type mismatch, argument %d.", szMember
, uiArgErr
); 
 955             wsprintf(szBuf
, L
"%s: Unknown error occurred.", szMember
); 
 964 #endif // wxUSE_OLE_AUTOMATION