X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/69f82505ec2cddcd3ecd8d8bed6af0bc3056e576..3988b3e819a2e336b8fcd90214c949f61069279b:/src/msw/ole/automtn.cpp?ds=sidebyside diff --git a/src/msw/ole/automtn.cpp b/src/msw/ole/automtn.cpp index 127b52b527..369dfec16f 100644 --- a/src/msw/ole/automtn.cpp +++ b/src/msw/ole/automtn.cpp @@ -22,8 +22,6 @@ #define wxUSE_OLE_AUTOMATION 0 #endif -#if wxUSE_OLE_AUTOMATION - #ifndef WX_PRECOMP #include "wx/log.h" #include "wx/math.h" @@ -56,17 +54,23 @@ #include "wx/datetime.h" #endif // wxUSE_DATETIME -static void ClearVariant(VARIANTARG *pvarg) ; -static void ReleaseVariant(VARIANTARG *pvarg) ; -// static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr); +#if wxUSE_OLE_AUTOMATION + +#include + +// Report an OLE error when calling the specified method to the user via wxLog. +static void +ShowException(const wxString& member, + HRESULT hr, + EXCEPINFO *pexcep = NULL, + unsigned int uiArgErr = 0); -/* - * wxAutomationObject - */ +// wxAutomationObject wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr) { m_dispatchPtr = dispatchPtr; + m_lcid = LOCALE_SYSTEM_DEFAULT; } wxAutomationObject::~wxAutomationObject() @@ -78,47 +82,59 @@ wxAutomationObject::~wxAutomationObject() } } +namespace +{ + +// A simple helper that ensures that VARIANT is destroyed on scope exit. +struct wxOleVariantArg : VARIANTARG +{ + wxOleVariantArg() { VariantInit(this); } + ~wxOleVariantArg() { VariantClear(this); } +}; + +} // anonymous namespace + + #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i])) // For Put/Get, no named arguments are allowed. +// WARNING: if args contain IDispatches, their reference count will be decreased +// by one after Invoke() returns! bool wxAutomationObject::Invoke(const wxString& member, int action, wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const { if (!m_dispatchPtr) return false; - // nonConstMember is necessary because the wxString class doesn't have enough consts... - wxString nonConstMember(member); - - int ch = nonConstMember.Find('.'); + int ch = member.Find('.'); if (ch != -1) { // Use dot notation to get the next object - wxString member2(nonConstMember.Left((size_t) ch)); - wxString rest(nonConstMember.Right(nonConstMember.length() - ch - 1)); + wxString member2(member.Left((size_t) ch)); + wxString rest(member.Right(member.length() - ch - 1)); wxAutomationObject obj; if (!GetObject(obj, member2)) return false; return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs); } - VARIANTARG vReturn; - ClearVariant(& vReturn); - - VARIANTARG* vReturnPtr = & vReturn; + wxOleVariantArg vReturn; + wxOleVariantArg* vReturnPtr = & vReturn; // Find number of names args int namedArgCount = 0; int i; for (i = 0; i < noArgs; i++) - if (!INVOKEARG(i).GetName().IsNull()) + { + if ( !INVOKEARG(i).GetName().empty() ) { namedArgCount ++; } + } int namedArgStringCount = namedArgCount + 1; - BSTR* argNames = new BSTR[namedArgStringCount]; - argNames[0] = wxConvertStringToOle(member); + wxVector argNames(namedArgStringCount, wxString()); + argNames[0] = member; // Note that arguments are specified in reverse order // (all totally logical; hey, we're dealing with OLE here.) @@ -126,30 +142,30 @@ bool wxAutomationObject::Invoke(const wxString& member, int action, int j = 0; for (i = 0; i < namedArgCount; i++) { - if (!INVOKEARG(i).GetName().IsNull()) + if ( !INVOKEARG(i).GetName().empty() ) { - argNames[(namedArgCount-j)] = wxConvertStringToOle(INVOKEARG(i).GetName()); + argNames[(namedArgCount-j)] = INVOKEARG(i).GetName(); j ++; } } // + 1 for the member name, + 1 again in case we're a 'put' - DISPID* dispIds = new DISPID[namedArgCount + 2]; + wxVector dispIds(namedArgCount + 2); HRESULT hr; DISPPARAMS dispparams; unsigned int uiArgErr; - EXCEPINFO excep; // Get the IDs for the member and its arguments. GetIDsOfNames expects the // member name as the first name, followed by argument names (if any). - hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, argNames, - 1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, dispIds); + hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, + // We rely on the fact that wxBasicString is + // just BSTR with some methods here. + reinterpret_cast(&argNames[0]), + 1 + namedArgCount, m_lcid, &dispIds[0]); if (FAILED(hr)) { -// ShowException(szMember, hr, NULL, 0); - delete[] argNames; - delete[] dispIds; + ShowException(member, hr); return false; } @@ -163,52 +179,35 @@ bool wxAutomationObject::Invoke(const wxString& member, int action, } // Convert the wxVariants to VARIANTARGs - VARIANTARG* oleArgs = new VARIANTARG[noArgs]; + wxVector oleArgs(noArgs); for (i = 0; i < noArgs; i++) { // Again, reverse args if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i])) - { - delete[] argNames; - delete[] dispIds; - delete[] oleArgs; return false; - } } - dispparams.rgdispidNamedArgs = dispIds + 1; - dispparams.rgvarg = oleArgs; + dispparams.rgdispidNamedArgs = &dispIds[0] + 1; + dispparams.rgvarg = oleArgs.empty() ? NULL : &oleArgs[0]; dispparams.cArgs = noArgs; dispparams.cNamedArgs = namedArgCount; - excep.pfnDeferredFillIn = NULL; + EXCEPINFO excep; + wxZeroMemory(excep); - hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT, + hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, m_lcid, (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr); - for (i = 0; i < namedArgStringCount; i++) - { - SysFreeString(argNames[i]); - } - delete[] argNames; - delete[] dispIds; - - for (i = 0; i < noArgs; i++) - ReleaseVariant(& oleArgs[i]) ; - delete[] oleArgs; - if (FAILED(hr)) { // display the exception information if appropriate: -// ShowException((const char*) member, hr, &excep, uiArgErr); + ShowException(member, hr, &excep, uiArgErr); // free exception structure information SysFreeString(excep.bstrSource); SysFreeString(excep.bstrDescription); SysFreeString(excep.bstrHelpFile); - if (vReturnPtr) - ReleaseVariant(vReturnPtr); return false; } else @@ -216,13 +215,19 @@ bool wxAutomationObject::Invoke(const wxString& member, int action, if (vReturnPtr) { // Convert result to wxVariant form - wxConvertOleToVariant(vReturn, retValue); + if (!wxConvertOleToVariant(vReturn, retValue)) + return false; // Mustn't release the dispatch pointer if (vReturn.vt == VT_DISPATCH) { vReturn.pdispVal = NULL; } - ReleaseVariant(& vReturn); + // Mustn't free the SAFEARRAY if it is contained in the retValue + if ((vReturn.vt & VT_ARRAY) && + retValue.GetType() == wxS("safearray")) + { + vReturn.parray = NULL; + } } } return true; @@ -469,6 +474,7 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop if (dispatch) { obj.SetDispatchPtr(dispatch); + obj.SetLCID(GetLCID()); return true; } else @@ -482,497 +488,198 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop if (dispatch) { obj.SetDispatchPtr(dispatch); + obj.SetLCID(GetLCID()); return true; } else return false; } -// Get a dispatch pointer from the current object associated -// with a class id -bool wxAutomationObject::GetInstance(const wxString& classId) const +namespace { - if (m_dispatchPtr) - return false; - - CLSID clsId; - IUnknown * pUnk = NULL; - - wxBasicString unicodeName(classId); - if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId))) - { - wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); - return false; - } - - if (FAILED(GetActiveObject(clsId, NULL, &pUnk))) - { - wxLogWarning(wxT("Cannot find an active object")); - return false; - } - - if (pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr) != S_OK) +HRESULT wxCLSIDFromProgID(const wxString& progId, CLSID& clsId) +{ + HRESULT hr = CLSIDFromProgID(wxBasicString(progId), &clsId); + if ( FAILED(hr) ) { - wxLogWarning(wxT("Cannot find IDispatch interface")); - return false; + wxLogSysError(hr, _("Failed to find CLSID of \"%s\""), progId); } - - return true; + return hr; } -// Get a dispatch pointer from a new object associated -// with the given class id -bool wxAutomationObject::CreateInstance(const wxString& classId) const +void *DoCreateInstance(const wxString& progId, const CLSID& clsId) { - if (m_dispatchPtr) - return false; - - CLSID clsId; - - wxBasicString unicodeName(classId); - - if (FAILED(CLSIDFromProgID((BSTR) unicodeName, &clsId))) - { - wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); - return false; - } - // get the server IDispatch interface // // NB: using CLSCTX_INPROC_HANDLER results in failure when getting // Automation interface for Microsoft Office applications so don't use // CLSCTX_ALL which includes it - if (FAILED(CoCreateInstance(clsId, NULL, CLSCTX_SERVER, IID_IDispatch, - (void**)&m_dispatchPtr))) + void *pDispatch = NULL; + HRESULT hr = CoCreateInstance(clsId, NULL, CLSCTX_SERVER, + IID_IDispatch, &pDispatch); + if (FAILED(hr)) { - wxLogWarning(wxT("Cannot start an instance of this class.")); - return false; + wxLogSysError(hr, _("Failed to create an instance of \"%s\""), progId); + return NULL; } - return true; + return pDispatch; } +} // anonymous namespace -WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant) +// Get a dispatch pointer from the current object associated +// with a ProgID +bool wxAutomationObject::GetInstance(const wxString& progId, int flags) const { - ClearVariant(&oleVariant); - if (variant.IsNull()) - { - oleVariant.vt = VT_NULL; - return true; - } - - wxString type(variant.GetType()); - - - if (type == wxT("long")) - { - oleVariant.vt = VT_I4; - oleVariant.lVal = variant.GetLong() ; - } - // cVal not always present -#ifndef __GNUWIN32__ - else if (type == wxT("char")) - { - oleVariant.vt=VT_I1; // Signed Char - oleVariant.cVal=variant.GetChar(); - } -#endif - else if (type == wxT("double")) - { - oleVariant.vt = VT_R8; - oleVariant.dblVal = variant.GetDouble(); - } - else if (type == wxT("bool")) - { - oleVariant.vt = VT_BOOL; - // 'bool' required for VC++ 4 apparently -#if (defined(__VISUALC__) && (__VISUALC__ <= 1000)) - oleVariant.bool = variant.GetBool(); -#else - oleVariant.boolVal = variant.GetBool(); -#endif - } - else if (type == wxT("string")) - { - wxString str( variant.GetString() ); - oleVariant.vt = VT_BSTR; - oleVariant.bstrVal = wxConvertStringToOle(str); - } -#if wxUSE_DATETIME - else if (type == wxT("datetime")) - { - wxDateTime date( variant.GetDateTime() ); - oleVariant.vt = VT_DATE; + if (m_dispatchPtr) + return false; - SYSTEMTIME st; - date.GetAsMSWSysTime(&st); + CLSID clsId; + HRESULT hr = wxCLSIDFromProgID(progId, clsId); + if (FAILED(hr)) + return false; - SystemTimeToVariantTime(&st, &oleVariant.date); - } -#endif - else if (type == wxT("void*")) - { - oleVariant.vt = VT_DISPATCH; - oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr(); - } - else if (type == wxT("list") || type == wxT("stringlist")) + IUnknown *pUnk = NULL; + hr = GetActiveObject(clsId, NULL, &pUnk); + if (FAILED(hr)) { - oleVariant.vt = VT_VARIANT | VT_ARRAY; - - SAFEARRAY *psa; - SAFEARRAYBOUND saBound; - VARIANTARG *pvargBase; - VARIANTARG *pvarg; - int i, j; - - int iCount = variant.GetCount(); - - saBound.lLbound = 0; - saBound.cElements = iCount; - - psa = SafeArrayCreate(VT_VARIANT, 1, &saBound); - if (psa == NULL) - return false; - - SafeArrayAccessData(psa, (void**)&pvargBase); - - pvarg = pvargBase; - for (i = 0; i < iCount; i++) + if ( flags & wxAutomationInstance_CreateIfNeeded ) { - // copy each string in the list of strings - wxVariant eachVariant(variant[i]); - if (!wxConvertVariantToOle(eachVariant, * pvarg)) + const_cast(this)-> + m_dispatchPtr = DoCreateInstance(progId, clsId); + if ( m_dispatchPtr ) + return true; + } + else + { + // Log an error except if we're supposed to fail silently when the + // error is that no current instance exists. + if ( hr != MK_E_UNAVAILABLE || + !(flags & wxAutomationInstance_SilentIfNone) ) { - // memory failure: back out and free strings alloc'ed up to - // now, and then the array itself. - pvarg = pvargBase; - for (j = 0; j < i; j++) - { - SysFreeString(pvarg->bstrVal); - pvarg++; - } - SafeArrayDestroy(psa); - return false; + wxLogSysError(hr, + _("Cannot get an active instance of \"%s\""), + progId); } - pvarg++; } - SafeArrayUnaccessData(psa); - - oleVariant.parray = psa; + return false; } - else + + hr = pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr); + if (FAILED(hr)) { - oleVariant.vt = VT_NULL; + wxLogSysError(hr, + _("Failed to get OLE automation interface for \"%s\""), + progId); return false; } + return true; } -#ifndef VT_TYPEMASK -#define VT_TYPEMASK 0xfff -#endif - -WXDLLEXPORT bool -wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant) +// Get a dispatch pointer from a new object associated +// with the given ProgID +bool wxAutomationObject::CreateInstance(const wxString& progId) const { - bool ok = true; - if ( oleVariant.vt & VT_ARRAY ) - { - - // Compute the total number of elements in all array dimensions - int cElements = 1; - for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ ) - cElements *= oleVariant.parray->rgsabound[cDims].cElements; - - // Get a pointer to the data - void* pvdata; - HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata); - if ( FAILED(hr) ) - return false; - - switch (oleVariant.vt & VT_TYPEMASK) - { - case VT_VARIANT: - { - variant.ClearList(); - VARIANTARG *variant_data=(VARIANTARG*)pvdata; - for ( int i = 0; i < cElements; i++ ) - { - VARIANTARG& oleElement = variant_data[i]; - wxVariant vElement; - if ( !wxConvertOleToVariant(oleElement, vElement) ) - { - ok = false; - variant.ClearList(); - break; - } - - variant.Append(vElement); - } - } - break; - - case VT_BSTR: - { - wxArrayString strings; - BSTR *string_val=(BSTR*)pvdata; - for ( int i = 0; i < cElements; ++i ) - { - wxString str=wxConvertStringFromOle(*string_val); - strings.Add(str); - ++string_val; - } - variant=strings; - } - break; - - default: - wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"), - oleVariant.vt & VT_TYPEMASK); - variant = wxVariant(); - ok = false; - break; - } - - SafeArrayUnaccessData(oleVariant.parray); - } - else if ( oleVariant.vt & VT_BYREF ) - { - switch ( oleVariant.vt & VT_TYPEMASK ) - { - case VT_VARIANT: - { - VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref); - if (!wxConvertOleToVariant(oleReference,variant)) - return false; - break; - } - - default: - wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"), - oleVariant.vt); - return false; - } - } - else // simply type (not array or reference) - { - switch ( oleVariant.vt & VT_TYPEMASK ) - { - case VT_BSTR: - { - wxString str(wxConvertStringFromOle(oleVariant.bstrVal)); - variant = str; - } - break; - - case VT_DATE: -#if wxUSE_DATETIME - { - SYSTEMTIME st; - VariantTimeToSystemTime(oleVariant.date, &st); - - wxDateTime date; - date.SetFromMSWSysTime(st); - variant = date; - } -#endif // wxUSE_DATETIME - break; - - case VT_I4: - variant = (long) oleVariant.lVal; - break; - - case VT_I2: - variant = (long) oleVariant.iVal; - break; - - case VT_BOOL: - variant = oleVariant.boolVal != 0; - break; - - case VT_R8: - variant = oleVariant.dblVal; - break; - - case VT_DISPATCH: - variant = (void*) oleVariant.pdispVal; - break; - - case VT_NULL: - variant.MakeNull(); - break; + if (m_dispatchPtr) + return false; - case VT_EMPTY: - break; // Ignore Empty Variant, used only during destruction of objects + CLSID clsId; + HRESULT hr = wxCLSIDFromProgID(progId, clsId); + if (FAILED(hr)) + return false; - default: - wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"), - oleVariant.vt,oleVariant.vt&VT_TYPEMASK); - return false; - } - } + const_cast(this)-> + m_dispatchPtr = DoCreateInstance(progId, clsId); - return ok; + return m_dispatchPtr != NULL; } -/* - * ClearVariant - * - * Zeros a variant structure without regard to current contents - */ -static void ClearVariant(VARIANTARG *pvarg) +LCID wxAutomationObject::GetLCID() const { - pvarg->vt = VT_EMPTY; - pvarg->wReserved1 = 0; - pvarg->wReserved2 = 0; - pvarg->wReserved3 = 0; - pvarg->lVal = 0; + return m_lcid; } -/* - * ReleaseVariant - * - * Clears a particular variant structure and releases any external objects - * or memory contained in the variant. Supports the data types listed above. - */ -static void ReleaseVariant(VARIANTARG *pvarg) +void wxAutomationObject::SetLCID(LCID lcid) { - VARTYPE vt; - VARIANTARG _huge *pvargArray; - LONG lLBound, lUBound, l; - - vt = (VARTYPE)(pvarg->vt & 0xfff); // mask off flags - - // check if an array. If so, free its contents, then the array itself. - if (V_ISARRAY(pvarg)) - { - // variant arrays are all this routine currently knows about. Since a - // variant can contain anything (even other arrays), call ourselves - // recursively. - if (vt == VT_VARIANT) - { - SafeArrayGetLBound(pvarg->parray, 1, &lLBound); - SafeArrayGetUBound(pvarg->parray, 1, &lUBound); - - if (lUBound > lLBound) - { - lUBound -= lLBound; - - SafeArrayAccessData(pvarg->parray, (void**)&pvargArray); - - for (l = 0; l < lUBound; l++) - { - ReleaseVariant(pvargArray); - pvargArray++; - } - - SafeArrayUnaccessData(pvarg->parray); - } - } - else - { - wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type")); - } - - // Free the array itself. - SafeArrayDestroy(pvarg->parray); - } - else - { - switch (vt) - { - case VT_DISPATCH: - if (pvarg->pdispVal) - pvarg->pdispVal->Release(); - break; - - case VT_BSTR: - SysFreeString(pvarg->bstrVal); - break; - - case VT_I2: - case VT_I4: - case VT_BOOL: - case VT_R8: - case VT_ERROR: // to avoid erroring on an error return from Excel - case VT_EMPTY: - case VT_DATE: - // no work for these types - break; - - default: - wxLogWarning(wxT("ReleaseVariant: Unknown type")); - break; - } - } - - ClearVariant(pvarg); + m_lcid = lcid; } -#if 0 - -void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr) +static void +ShowException(const wxString& member, + HRESULT hr, + EXCEPINFO *pexcep, + unsigned int uiArgErr) { - TCHAR szBuf[512]; - + wxString message; switch (GetScode(hr)) { case DISP_E_UNKNOWNNAME: - wsprintf(szBuf, L"%s: Unknown name or named argument.", szMember); + message = _("Unknown name or named argument."); break; case DISP_E_BADPARAMCOUNT: - wsprintf(szBuf, L"%s: Incorrect number of arguments.", szMember); + message = _("Incorrect number of arguments."); break; case DISP_E_EXCEPTION: - wsprintf(szBuf, L"%s: Error %d: ", szMember, pexcep->wCode); - if (pexcep->bstrDescription != NULL) - lstrcat(szBuf, pexcep->bstrDescription); + if ( pexcep ) + { + if ( pexcep->bstrDescription ) + message << pexcep->bstrDescription << wxS(" "); + message += wxString::Format(wxS("error code %u"), pexcep->wCode); + } else - lstrcat(szBuf, L"<>"); + { + message = _("Unknown exception"); + } break; case DISP_E_MEMBERNOTFOUND: - wsprintf(szBuf, L"%s: method or property not found.", szMember); + message = _("Method or property not found."); break; case DISP_E_OVERFLOW: - wsprintf(szBuf, L"%s: Overflow while coercing argument values.", szMember); + message = _("Overflow while coercing argument values."); break; case DISP_E_NONAMEDARGS: - wsprintf(szBuf, L"%s: Object implementation does not support named arguments.", - szMember); + message = _("Object implementation does not support named arguments."); break; case DISP_E_UNKNOWNLCID: - wsprintf(szBuf, L"%s: The locale ID is unknown.", szMember); + message = _("The locale ID is unknown."); break; case DISP_E_PARAMNOTOPTIONAL: - wsprintf(szBuf, L"%s: Missing a required parameter.", szMember); + message = _("Missing a required parameter."); break; case DISP_E_PARAMNOTFOUND: - wsprintf(szBuf, L"%s: Argument not found, argument %d.", szMember, uiArgErr); + message.Printf(_("Argument %u not found."), uiArgErr); break; case DISP_E_TYPEMISMATCH: - wsprintf(szBuf, L"%s: Type mismatch, argument %d.", szMember, uiArgErr); + message.Printf(_("Type mismatch in argument %u."), uiArgErr); + break; + + case ERROR_FILE_NOT_FOUND: + message = _("The system cannot find the file specified."); + break; + + case REGDB_E_CLASSNOTREG: + message = _("Class not registered."); break; default: - wsprintf(szBuf, L"%s: Unknown error occurred.", szMember); + message.Printf(_("Unknown error %08x"), hr); break; } - wxLogWarning(szBuf); + wxLogError(_("OLE Automation error in %s: %s"), member, message); } -#endif - #endif // wxUSE_OLE_AUTOMATION