X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/27d7687903b04c56878597fefccf3daafd0a58fa..be10c7f969bb460dc79bd8946d59bf54c98ac660:/src/msw/ole/automtn.cpp diff --git a/src/msw/ole/automtn.cpp b/src/msw/ole/automtn.cpp index f047bda3d4..b3f5f72e4a 100644 --- a/src/msw/ole/automtn.cpp +++ b/src/msw/ole/automtn.cpp @@ -4,7 +4,6 @@ // Author: Julian Smart // Modified by: // Created: 11/6/98 -// RCS-ID: $Id$ // Copyright: (c) 1998, Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -56,18 +55,21 @@ #if wxUSE_OLE_AUTOMATION -// Report an OLE error to the user via wxLog. +#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, - unsigned int uiArgErr); + EXCEPINFO *pexcep = NULL, + unsigned int uiArgErr = 0); // wxAutomationObject wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr) { m_dispatchPtr = dispatchPtr; + m_lcid = LOCALE_SYSTEM_DEFAULT; } wxAutomationObject::~wxAutomationObject() @@ -79,47 +81,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; - VariantInit(& 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.) @@ -127,15 +141,15 @@ 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; @@ -143,13 +157,14 @@ bool wxAutomationObject::Invoke(const wxString& member, int action, // 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(member, hr, NULL, 0); - delete[] argNames; - delete[] dispIds; + ShowException(member, hr); return false; } @@ -163,41 +178,25 @@ 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; 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++) - VariantClear(& oleArgs[i]) ; - delete[] oleArgs; - if (FAILED(hr)) { // display the exception information if appropriate: @@ -208,8 +207,6 @@ bool wxAutomationObject::Invoke(const wxString& member, int action, SysFreeString(excep.bstrDescription); SysFreeString(excep.bstrHelpFile); - if (vReturnPtr) - VariantClear(vReturnPtr); return false; } else @@ -217,13 +214,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; } - VariantClear(& 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; @@ -470,6 +473,7 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop if (dispatch) { obj.SetDispatchPtr(dispatch); + obj.SetLCID(GetLCID()); return true; } else @@ -483,46 +487,92 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop if (dispatch) { obj.SetDispatchPtr(dispatch); + obj.SetLCID(GetLCID()); return true; } else return false; } +namespace +{ + +HRESULT wxCLSIDFromProgID(const wxString& progId, CLSID& clsId) +{ + HRESULT hr = CLSIDFromProgID(wxBasicString(progId), &clsId); + if ( FAILED(hr) ) + { + wxLogSysError(hr, _("Failed to find CLSID of \"%s\""), progId); + } + return hr; +} + +void *DoCreateInstance(const wxString& progId, const CLSID& clsId) +{ + // 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 + void *pDispatch = NULL; + HRESULT hr = CoCreateInstance(clsId, NULL, CLSCTX_SERVER, + IID_IDispatch, &pDispatch); + if (FAILED(hr)) + { + wxLogSysError(hr, _("Failed to create an instance of \"%s\""), progId); + return NULL; + } + + return pDispatch; +} + +} // anonymous namespace + // Get a dispatch pointer from the current object associated // with a ProgID -bool wxAutomationObject::GetInstance(const wxString& progId) const +bool wxAutomationObject::GetInstance(const wxString& progId, int flags) const { if (m_dispatchPtr) return false; - HRESULT hr; CLSID clsId; - IUnknown * pUnk = NULL; - - wxBasicString unicodeName(progId); - - hr = CLSIDFromProgID((BSTR) unicodeName, &clsId); + HRESULT hr = wxCLSIDFromProgID(progId, clsId); if (FAILED(hr)) - { - ShowException(progId, hr, NULL, 0); - wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); return false; - } + IUnknown *pUnk = NULL; hr = GetActiveObject(clsId, NULL, &pUnk); if (FAILED(hr)) { - ShowException(progId, hr, NULL, 0); - wxLogWarning(wxT("Cannot find an active object")); + if ( flags & wxAutomationInstance_CreateIfNeeded ) + { + 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) ) + { + wxLogSysError(hr, + _("Cannot get an active instance of \"%s\""), + progId); + } + } + return false; } hr = pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr); if (FAILED(hr)) { - ShowException(progId, hr, NULL, 0); - wxLogWarning(wxT("Cannot find IDispatch interface")); + wxLogSysError(hr, + _("Failed to get OLE automation interface for \"%s\""), + progId); return false; } @@ -536,34 +586,25 @@ bool wxAutomationObject::CreateInstance(const wxString& progId) const if (m_dispatchPtr) return false; - HRESULT hr; CLSID clsId; - - wxBasicString unicodeName(progId); - - hr = CLSIDFromProgID((BSTR) unicodeName, &clsId); + HRESULT hr = wxCLSIDFromProgID(progId, clsId); if (FAILED(hr)) - { - ShowException(progId, hr, NULL, 0); - 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 - hr = CoCreateInstance(clsId, NULL, CLSCTX_SERVER, IID_IDispatch, - (void**)&m_dispatchPtr); - if (FAILED(hr)) - { - ShowException(progId, hr, NULL, 0); - wxLogWarning(wxT("Could not start an instance of this class.")); - return false; - } + const_cast(this)-> + m_dispatchPtr = DoCreateInstance(progId, clsId); - return true; + return m_dispatchPtr != NULL; +} + +LCID wxAutomationObject::GetLCID() const +{ + return m_lcid; +} + +void wxAutomationObject::SetLCID(LCID lcid) +{ + m_lcid = lcid; } static void @@ -576,70 +617,68 @@ ShowException(const wxString& member, switch (GetScode(hr)) { case DISP_E_UNKNOWNNAME: - message = wxT("Unknown name or named argument."); + message = _("Unknown name or named argument."); break; case DISP_E_BADPARAMCOUNT: - message = wxT("Incorrect number of arguments."); + message = _("Incorrect number of arguments."); break; case DISP_E_EXCEPTION: + if ( pexcep ) + { + if ( pexcep->bstrDescription ) + message << pexcep->bstrDescription << wxS(" "); + message += wxString::Format(wxS("error code %u"), pexcep->wCode); + } + else { - message = wxT("Error Code ("); - message << pexcep->wCode ;// unsigned short - message += wxT(")"); - if (pexcep->bstrDescription != NULL) - message += pexcep->bstrDescription; - else - message += wxT("<>"); + message = _("Unknown exception"); } break; case DISP_E_MEMBERNOTFOUND: - message = wxT("Method or property not found."); + message = _("Method or property not found."); break; case DISP_E_OVERFLOW: - message = wxT("Overflow while coercing argument values."); + message = _("Overflow while coercing argument values."); break; case DISP_E_NONAMEDARGS: - message = wxT("Object implementation does not support named arguments."); + message = _("Object implementation does not support named arguments."); break; case DISP_E_UNKNOWNLCID: - message = wxT("The locale ID is unknown."); + message = _("The locale ID is unknown."); break; case DISP_E_PARAMNOTOPTIONAL: - message = wxT("Missing a required parameter."); + message = _("Missing a required parameter."); break; case DISP_E_PARAMNOTFOUND: - message = wxT("Argument not found, argument."); - message << uiArgErr; + message.Printf(_("Argument %u not found."), uiArgErr); break; case DISP_E_TYPEMISMATCH: - message = wxT("Type mismatch, argument."); - message << uiArgErr; + message.Printf(_("Type mismatch in argument %u."), uiArgErr); break; case ERROR_FILE_NOT_FOUND: - message = wxT("The system cannot find the file specified."); + message = _("The system cannot find the file specified."); break; case REGDB_E_CLASSNOTREG: - message = wxT("Class not registered."); + message = _("Class not registered."); break; default: - message = wxT("Unknown error occurred. Return value is "); - message << hr; + message.Printf(_("Unknown error %08x"), hr); break; } - wxLogDebug("OLE Automation error in %s: %s", member, message); + wxLogError(_("OLE Automation error in %s: %s"), member, message); } #endif // wxUSE_OLE_AUTOMATION