diff options
Diffstat (limited to 'extensions/source/ole/oleobjw.cxx')
-rwxr-xr-x | extensions/source/ole/oleobjw.cxx | 2541 |
1 files changed, 2541 insertions, 0 deletions
diff --git a/extensions/source/ole/oleobjw.cxx b/extensions/source/ole/oleobjw.cxx new file mode 100755 index 000000000000..949fb6c7c9b2 --- /dev/null +++ b/extensions/source/ole/oleobjw.cxx @@ -0,0 +1,2541 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "ole2uno.hxx" +#include "rtl/ustrbuf.hxx" + + +#include "osl/diagnose.h" +#include "osl/doublecheckedlocking.h" +#include "osl/thread.h" + +#include "boost/scoped_array.hpp" +#include <com/sun/star/script/FailReason.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/FinishEngineEvent.hpp> +#include <com/sun/star/script/InterruptReason.hpp> +#include <com/sun/star/script/XEngineListener.hpp> +#include <com/sun/star/script/XDebugging.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/script/ContextInformation.hpp> +#include <com/sun/star/script/FinishReason.hpp> +#include <com/sun/star/script/XEngine.hpp> +#include <com/sun/star/script/InterruptEngineEvent.hpp> +#include <com/sun/star/script/XLibraryAccess.hpp> +#include <com/sun/star/bridge/ModelDependent.hpp> + +#include "com/sun/star/bridge/oleautomation/NamedArgument.hpp" +#include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp" + +#include <typelib/typedescription.hxx> +#include <rtl/uuid.h> +#include <rtl/memory.h> +#include <rtl/ustring.hxx> + +#include "jscriptclasses.hxx" + +#include "oleobjw.hxx" +#include "unoobjw.hxx" +#include <stdio.h> +using namespace std; +using namespace boost; +using namespace osl; +using namespace rtl; +using namespace cppu; +using namespace com::sun::star::script; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::oleautomation; +using namespace com::sun::star::bridge::ModelDependent; +using namespace ::com::sun::star; + +#define JSCRIPT_ID_PROPERTY L"_environment" +#define JSCRIPT_ID L"jscript" +namespace ole_adapter +{ + + +// key: XInterface pointer created by Invocation Adapter Factory +// value: XInterface pointer to the wrapper class. +// Entries to the map are made within +// Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType); +// Entries are being deleted if the wrapper class's destructor has been +// called. +// Before UNO object is wrapped to COM object this map is checked +// to see if the UNO object is already a wrapper. +hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap; +// key: XInterface of the wrapper object. +// value: XInterface of the Interface created by the Invocation Adapter Factory. +// A COM wrapper is responsible for removing the corresponding entry +// in AdapterToWrappperMap if it is being destroyed. Because the wrapper does not +// know about its adapted interface it uses WrapperToAdapterMap to get the +// adapted interface which is then used to locate the entry in AdapterToWrapperMap. +hash_map<sal_uInt32,sal_uInt32> WrapperToAdapterMap; + +hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap; +/***************************************************************************** + + class implementation IUnknownWrapper_Impl + +*****************************************************************************/ + +IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): + UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass), + m_pxIdlClass( NULL), m_eJScript( JScriptUndefined), + m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false) +{ +} + + +IUnknownWrapper_Impl::~IUnknownWrapper_Impl() +{ + o2u_attachCurrentThread(); + MutexGuard guard(getBridgeMutex()); + XInterface * xIntRoot = (OWeakObject *)this; +#if OSL_DEBUG_LEVEL > 0 + acquire(); // make sure we don't delete us twice because of Reference + OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot ); +#endif + + // remove entries in global maps + typedef hash_map<sal_uInt32, sal_uInt32>::iterator _IT; + _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot); + if( it != WrapperToAdapterMap.end()) + { + sal_uInt32 adapter= it->second; + + AdapterToWrapperMap.erase( adapter); + WrapperToAdapterMap.erase( it); + } + + IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_spUnknown.p); + if(it_c != ComPtrToWrapperMap.end()) + ComPtrToWrapperMap.erase(it_c); + +#if OSL_DEBUG_LEVEL > 0 + fprintf(stderr,"[automation bridge] ComPtrToWrapperMap contains: %i \n", + ComPtrToWrapperMap.size()); +#endif +} + +Any IUnknownWrapper_Impl::queryInterface(const Type& t) + throw (RuntimeException) +{ + if (t == getCppuType(static_cast<Reference<XDefaultMethod>*>( 0)) && !m_bHasDfltMethod ) + return Any(); + if (t == getCppuType(static_cast<Reference<XDefaultProperty>*>( 0)) && !m_bHasDfltProperty ) + return Any(); + if (t == getCppuType(static_cast<Reference<XInvocation>*>( 0)) && !m_spDispatch) + return Any(); + + return WeakImplHelper7<XInvocation, XBridgeSupplier2, + XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation>::queryInterface(t); +} + +Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void) + throw (RuntimeException ) +{ + Reference<XIntrospectionAccess> ret; + + return ret; +} + + + +Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName, + const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, + Sequence< Any >& aOutParam ) + throw(IllegalArgumentException, CannotConvertException, InvocationTargetException, + RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + + Any ret; + + try + { + o2u_attachCurrentThread(); + + TypeDescription methodDesc; + getMethodInfo(aFunctionName, methodDesc); + if( methodDesc.is()) + { + ret = invokeWithDispIdUnoTlb(aFunctionName, + aParams, + aOutParamIndex, + aOutParam); + } + else + { + ret= invokeWithDispIdComTlb( aFunctionName, + aParams, + aOutParamIndex, + aOutParam); + } + } + catch (IllegalArgumentException &) + { + throw; + } + catch (CannotConvertException &) + { + throw; + } + catch (BridgeRuntimeError & e) + { + throw RuntimeException(e.message, Reference<XInterface>()); + } + catch (Exception & e) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::invoke ! Message : \n") + + e.Message, Reference<XInterface>()); + + } + catch(...) + { + throw RuntimeException( + OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::Invoke !"), Reference<XInterface>()); + } + return ret; +} + +void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName, + const Any& aValue ) + throw(UnknownPropertyException, CannotConvertException, InvocationTargetException, + RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + try + { + o2u_attachCurrentThread(); + + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + //check if there is such a property at all or if it is read only + if ( ! aDescPut && ! aDescGet && ! aVarDesc) + { + OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName + + OUSTR("\" is not supported")); + throw UnknownPropertyException(msg, Reference<XInterface>()); + } + + if ( (! aDescPut && aDescGet) || aVarDesc + && aVarDesc->wVarFlags == VARFLAG_FREADONLY ) + { + //read-only + OUString msg(OUSTR("[automation bridge] Property ") + aPropertyName + + OUSTR(" is read-only")); + OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding()); + OSL_ENSURE(0, sMsg.getStr()); + // ignore silently + return; + } + + HRESULT hr= S_OK; + DISPPARAMS dispparams; + CComVariant varArg; + CComVariant varRefArg; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + + // converting UNO value to OLE variant + DISPID dispidPut= DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = &dispidPut; + dispparams.cArgs = 1; + dispparams.cNamedArgs = 1; + dispparams.rgvarg = & varArg; + + OSL_ASSERT(aDescPut || aVarDesc); + + VARTYPE vt = 0; + DISPID dispid = 0; + INVOKEKIND invkind = INVOKE_PROPERTYPUT; + //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT, + //DISPATCH_PROPERTYPUTREF) + if (aDescPut) + { + vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc); + dispid = aDescPut->memid; + invkind = aDescPut->invkind; + } + else + { + vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc); + dispid = aVarDesc->memid; + if (vt == VT_UNKNOWN || vt == VT_DISPATCH || + (vt & VT_ARRAY) || (vt & VT_BYREF)) + { + invkind = INVOKE_PROPERTYPUTREF; + } + } + + // convert the uno argument + if (vt & VT_BYREF) + { + anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) ); + varArg.vt = vt; + if( (vt & VT_TYPEMASK) == VT_VARIANT) + varArg.byref = & varRefArg; + else if ((vt & VT_TYPEMASK) == VT_DECIMAL) + varArg.byref = & varRefArg.decVal; + else + varArg.byref = & varRefArg.byref; + } + else + { + anyToVariant(& varArg, aValue, vt); + } + // call to IDispatch + hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ), + &dispparams, & varResult, & excepinfo, &uArgErr); + + // lookup error code + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw RuntimeException(); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(); + break; + case DISP_E_EXCEPTION: + throw InvocationTargetException(); + break; + case DISP_E_MEMBERNOTFOUND: + throw UnknownPropertyException(); + break; + case DISP_E_NONAMEDARGS: + throw RuntimeException(); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ; + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>( + static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + } + catch (CannotConvertException &) + { + throw; + } + catch (UnknownPropertyException &) + { + throw; + } + catch (BridgeRuntimeError& e) + { + throw RuntimeException( + e.message, Reference<XInterface>()); + } + catch (Exception & e) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::setValue ! Message : \n") + + e.Message, Reference<XInterface>()); + + } + catch (...) + { + throw RuntimeException( + OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::setValue !"), Reference<XInterface>()); + } +} + +Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName ) + throw(UnknownPropertyException, RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + Any ret; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + // I was going to implement an XServiceInfo interface to allow the type + // of the automation object to be exposed.. but it seems + // from looking at comments in the code that it is possible for + // this object to actually wrap an UNO object ( I guess if automation is + // used from MSO to create Openoffice objects ) Therefore, those objects + // will more than likely already have their own XServiceInfo interface. + // Instead here I chose a name that should be illegal both in COM and + // UNO ( from an IDL point of view ) therefore I think this is a safe + // hack + if ( aPropertyName.equals( rtl::OUString::createFromAscii("$GetTypeName") )) + { + if ( pInfo && m_sTypeName.getLength() == 0 ) + { + m_sTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("IDispatch") ); + CComBSTR sName; + + if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) ) + { + rtl::OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))); + if ( sTmp.indexOf('_') == 0 ) + sTmp = sTmp.copy(1); + // do we own the memory for pTypeLib, msdn doco is vague + // I'll assume we do + CComPtr< ITypeLib > pTypeLib; + unsigned int index; + if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) ) + { + if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) ) + { + rtl::OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))); + m_sTypeName = sLibName.concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".") ) ).concat( sTmp ); + + } + } + } + + } + ret <<= m_sTypeName; + return ret; + } + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( ! aDescGet && ! aDescPut && ! aVarDesc) + { + //property not found + OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName + + OUSTR("\" is not supported")); + throw UnknownPropertyException(msg, Reference<XInterface>()); + } + // write-only should not be possible + OSL_ASSERT( aDescGet || ! aDescPut); + + HRESULT hr; + DISPPARAMS dispparams = {0, 0, 0, 0}; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + DISPID dispid; + if (aDescGet) + dispid = aDescGet->memid; + else if (aVarDesc) + dispid = aVarDesc->memid; + else + dispid = aDescPut->memid; + + hr = m_spDispatch->Invoke(dispid, + IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_PROPERTYGET, + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (hr == S_OK) + { + // If the com object implements uno interfaces then we have + // to convert the attribute into the expected type. + TypeDescription attrInfo; + getAttributeInfo(aPropertyName, attrInfo); + if( attrInfo.is() ) + variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef)); + else + variantToAny(&varResult, ret); + } + + // lookup error code + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_EXCEPTION: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_MEMBERNOTFOUND: + throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_NONAMEDARGS: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_OVERFLOW: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_PARAMNOTFOUND: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_TYPEMISMATCH: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + default: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + } + } + catch (UnknownPropertyException& ) + { + throw; + } + catch (BridgeRuntimeError& e) + { + throw RuntimeException( + e.message, Reference<XInterface>()); + } + catch (Exception & e) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::getValue ! Message : \n") + + e.Message, Reference<XInterface>()); + } + catch (...) + { + throw RuntimeException( + OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::getValue !"), Reference<XInterface>()); + } + return ret; +} + +sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName ) + throw(RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + sal_Bool ret = sal_False; + + try + { + o2u_attachCurrentThread(); + ITypeInfo* pInfo = getTypeInfo(); + FuncDesc aDesc(pInfo); + getFuncDesc(aName, & aDesc); + // Automation properties can have arguments. Those are treated as methods and + //are called through XInvocation::invoke. + if ( ! aDesc) + { + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc); + if (aDescGet && aDescGet->cParams > 0 + || aDescPut && aDescPut->cParams > 0) + ret = sal_True; + } + else + ret = sal_True; + } + catch (BridgeRuntimeError& e) + { + throw RuntimeException(e.message, Reference<XInterface>()); + } + catch (Exception & e) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::hasMethod ! Message : \n") + + e.Message, Reference<XInterface>()); + } + catch (...) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::hasMethod !"), Reference<XInterface>());; + } + return ret; +} + +sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName ) + throw(RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException(OUSTR("[automation bridge] The object does not have an " + "IDispatch interface"), Reference<XInterface>()); + return sal_False; + } + sal_Bool ret = sal_False; + try + { + o2u_attachCurrentThread(); + + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc); + // Automation properties can have parameters. If so, we access them through + // XInvocation::invoke. Thas is, hasProperty must return false for such a + // property + if (aVarDesc + || aDescPut && aDescPut->cParams == 0 + || aDescGet && aDescGet->cParams == 0) + { + ret = sal_True; + } + } + catch (BridgeRuntimeError& e) + { + throw RuntimeException(e.message, Reference<XInterface>()); + } + catch (Exception & e) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::hasProperty ! Message : \n") + + e.Message, Reference<XInterface>()); + + } + catch (...) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::hasProperty !"), Reference<XInterface>()); + } + return ret; +} + +Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject, + const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType, + sal_Int16 destModelType ) + throw( IllegalArgumentException, RuntimeException) +{ + Any ret; + o2u_attachCurrentThread(); + + if ( + (sourceModelType == UNO) && + (destModelType == OLE) && + (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE) + ) + { + Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue()); + Reference<XInterface> xSelf( (OWeakObject*)this); + + if (xInt == xSelf) + { + VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT)); + + VariantInit(pVariant); + if (m_bOriginalDispatch == sal_True) + { + pVariant->vt = VT_DISPATCH; + pVariant->pdispVal = m_spDispatch; + pVariant->pdispVal->AddRef(); + } + else + { + pVariant->vt = VT_UNKNOWN; + pVariant->punkVal = m_spUnknown; + pVariant->punkVal->AddRef(); + } + + ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0)); + } + } + + return ret; +} +/** @internal + @exception IllegalArgumentException + @exception CannotConvertException + @exception InvocationTargetException + @RuntimeException +*/ +Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam) +{ + Any ret; + HRESULT hr= S_OK; + + sal_Int32 parameterCount= Params.getLength(); + sal_Int32 outParameterCount= 0; + typelib_InterfaceMethodTypeDescription* pMethod= NULL; + TypeDescription methodDesc; + getMethodInfo(sFunctionName, methodDesc); + + // We need to know whether the IDispatch is from a JScript object. + // Then out and in/out parameters have to be treated differently than + // with common COM objects. + sal_Bool bJScriptObject= isJScriptObject(); + scoped_array<CComVariant> sarParams; + scoped_array<CComVariant> sarParamsRef; + CComVariant *pVarParams= NULL; + CComVariant *pVarParamsRef= NULL; + sal_Bool bConvRet= sal_True; + + if( methodDesc.is()) + { + pMethod = (typelib_InterfaceMethodTypeDescription* )methodDesc.get(); + parameterCount = pMethod->nParams; + // Create the Array for the array being passed in DISPPARAMS + // the array also contains the outparameter (but not the values) + if( pMethod->nParams > 0) + { + sarParams.reset(new CComVariant[ parameterCount]); + pVarParams = sarParams.get(); + } + + // Create the Array for the out an in/out parameter. These values + // are referenced by the VT_BYREF VARIANTs in DISPPARAMS. + // We need to find out the number of out and in/out parameter. + for( sal_Int32 i=0; i < parameterCount; i++) + { + if( pMethod->pParams[i].bOut) + outParameterCount++; + } + + if( !bJScriptObject) + { + sarParamsRef.reset(new CComVariant[outParameterCount]); + pVarParamsRef = sarParamsRef.get(); + // build up the parameters for IDispatch::Invoke + sal_Int32 outParamIndex=0; + int i = 0; + try + { + for( i= 0; i < parameterCount; i++) + { + // In parameter + if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut) + { + anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); + } + // Out parameter + in/out parameter + else if( pMethod->pParams[i].bOut == sal_True) + { + CComVariant var; + if(pMethod->pParams[i].bIn) + { + anyToVariant( & var,Params[i]); + pVarParamsRef[outParamIndex] = var; + } + + switch( pMethod->pParams[i].pTypeRef->eTypeClass) + { + case TypeClass_INTERFACE: + case TypeClass_STRUCT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt= VT_DISPATCH; + pVarParamsRef[ outParamIndex].pdispVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF; + pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal; + break; + case TypeClass_ENUM: + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_I4; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF; + pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal; + break; + case TypeClass_SEQUENCE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT; + pVarParamsRef[ outParamIndex].parray= NULL; + } + pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT; + pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray; + break; + case TypeClass_ANY: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_EMPTY; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; + pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex]; + break; + case TypeClass_BOOLEAN: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_BOOL; + pVarParamsRef[ outParamIndex].boolVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF; + pVarParams[parameterCount - i -1].pboolVal = + & pVarParamsRef[outParamIndex].boolVal; + break; + + case TypeClass_STRING: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_BSTR; + pVarParamsRef[ outParamIndex].bstrVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF; + pVarParams[parameterCount - i -1].pbstrVal= + & pVarParamsRef[outParamIndex].bstrVal; + break; + + case TypeClass_FLOAT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_R4; + pVarParamsRef[ outParamIndex].fltVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF; + pVarParams[parameterCount - i -1].pfltVal = + & pVarParamsRef[outParamIndex].fltVal; + break; + case TypeClass_DOUBLE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_R8; + pVarParamsRef[ outParamIndex].dblVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF; + pVarParams[parameterCount - i -1].pdblVal= + & pVarParamsRef[outParamIndex].dblVal; + break; + case TypeClass_BYTE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_UI1; + pVarParamsRef[ outParamIndex].bVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF; + pVarParams[parameterCount - i -1].pbVal= + & pVarParamsRef[outParamIndex].bVal; + break; + case TypeClass_CHAR: + case TypeClass_SHORT: + case TypeClass_UNSIGNED_SHORT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_I2; + pVarParamsRef[ outParamIndex].iVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF; + pVarParams[parameterCount - i -1].piVal= + & pVarParamsRef[outParamIndex].iVal; + break; + + default: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_EMPTY; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; + pVarParams[parameterCount - i -1].pvarVal = + & pVarParamsRef[outParamIndex]; + } + outParamIndex++; + } // end else if + } // end for + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + else // it is an JScriptObject + { + int i = 0; + try + { + for( ; i< parameterCount; i++) + { + // In parameter + if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut) + { + anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); + } + // Out parameter + in/out parameter + else if( pMethod->pParams[i].bOut == sal_True) + { + CComObject<JScriptOutParam>* pParamObject; + if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject))) + { + CComPtr<IUnknown> pUnk(pParamObject->GetUnknown()); +#ifdef __MINGW32__ + CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk); +#else + CComQIPtr<IDispatch> pDisp( pUnk); +#endif + + pVarParams[ parameterCount - i -1].vt= VT_DISPATCH; + pVarParams[ parameterCount - i -1].pdispVal= pDisp; + pVarParams[ parameterCount - i -1].pdispVal->AddRef(); + // if the param is in/out then put the parameter on index 0 + if( pMethod->pParams[i].bIn == sal_True ) // in / out + { + CComVariant varParam; + anyToVariant( &varParam, Params.getConstArray()[i]); + CComDispatchDriver dispDriver( pDisp); + if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam))) + throw BridgeRuntimeError( + OUSTR("[automation bridge]IUnknownWrapper_Impl::" + "invokeWithDispIdUnoTlb\n" + "Could not set property \"0\" for the in/out " + "param!")); + + } + } + else + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]IUnknownWrapper_Impl::" + "invokeWithDispIdUnoTlb\n" + "Could not create out parameter at index: ") + + OUString::valueOf((sal_Int32) i)); + } + + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + } + // No type description Available, that is we have to deal with a COM component, + // that does not implements UNO interfaces ( IDispatch based) + else + { + //We should not run into this block, because invokeWithDispIdComTlb should + //have been called instead. + OSL_ASSERT(0); + } + + + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0}; + // Get the DISPID + FuncDesc aDesc(getTypeInfo()); + getFuncDesc(sFunctionName, & aDesc); + // invoking OLE method + hr = m_spDispatch->Invoke(aDesc->memid, + IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_METHOD, + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (hr == S_OK) + { + if( outParameterCount && pMethod) + { + OutParamIndex.realloc( outParameterCount); + OutParam.realloc( outParameterCount); + sal_Int32 outIndex=0; + int i = 0; + try + { + for( ; i < parameterCount; i++) + { + if( pMethod->pParams[i].bOut ) + { + OutParamIndex[outIndex]= (sal_Int16) i; + Any outAny; + if( !bJScriptObject) + { + variantToAny( &pVarParamsRef[outIndex], outAny, + Type(pMethod->pParams[i].pTypeRef), sal_False); + OutParam[outIndex++]= outAny; + } + else //JScriptObject + { + if( pVarParams[i].vt == VT_DISPATCH) + { + CComDispatchDriver pDisp( pVarParams[i].pdispVal); + if( pDisp) + { + CComVariant varOut; + if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut))) + { + variantToAny( &varOut, outAny, + Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False); + OutParam[outParameterCount - 1 - outIndex++]= outAny; + } + else + bConvRet= sal_False; + } + else + bConvRet= sal_False; + } + else + bConvRet= sal_False; + } + } + if( !bConvRet) break; + } + } + catch(IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch(CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + // return value, no type information available + if ( bConvRet) + { + try + { + if( pMethod ) + variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False); + else + variantToAny(&varResult, ret, sal_False); + } + catch (IllegalArgumentException & e) + { + e.Message = + OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n" + "Could not convert return value! \n Message: \n") + e.Message; + throw; + } + catch (CannotConvertException & e) + { + e.Message = + OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n" + "Could not convert return value! \n Message: \n") + e.Message; + throw; + } + } + } + + if( !bConvRet) // conversion of return or out parameter failed + throw CannotConvertException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Call to COM object failed. Conversion of return or out value failed")), + Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN, + FailReason::UNKNOWN, 0);// lookup error code + // conversion of return or out parameter failed + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException(); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(); + break; + case DISP_E_EXCEPTION: + throw InvocationTargetException(); + break; + case DISP_E_MEMBERNOTFOUND: + throw IllegalArgumentException(); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException(); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>( + static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException() ; + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException() ; + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + + return ret; +} + + + +// -------------------------- +// XInitialization +void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException) +{ + // 1.parameter is IUnknown + // 2.parameter is a boolean which indicates if the the COM pointer was a IUnknown or IDispatch + // 3.parameter is a Sequence<Type> + o2u_attachCurrentThread(); + OSL_ASSERT(aArguments.getLength() == 3); + + m_spUnknown= *(IUnknown**) aArguments[0].getValue(); +#ifdef __MINGW32__ + m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p)); +#else + m_spUnknown.QueryInterface( & m_spDispatch.p); +#endif + + aArguments[1] >>= m_bOriginalDispatch; + aArguments[2] >>= m_seqTypes; + + ITypeInfo* pType = NULL; + try + { + // a COM object implementation that has no TypeInfo is still a legal COM object; + // such objects can at least be transported through UNO using the bridge + // so we should allow to create wrappers for them as well + pType = getTypeInfo(); + } + catch( BridgeRuntimeError& ) + {} + catch( Exception& ) + {} + + if ( pType ) + { + try + { + // Get Default member + CComBSTR defaultMemberName; + if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) ) + { + OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName))); + FuncDesc aDescGet(pType); + FuncDesc aDescPut(pType); + VarDesc aVarDesc(pType); + // see if this is a property first ( more likely to be a property then a method ) + getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc); + + if ( !aDescGet && !aDescPut ) + { + getFuncDesc( usName, &aDescGet ); + if ( !aDescGet ) + throw BridgeRuntimeError( OUSTR("[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " ) + usName ); + } + // now for some funny heuristics to make basic understand what to do + // a single aDescGet ( that doesn't take any params ) would be + // a read only ( defaultmember ) property e.g. this object + // should implement XDefaultProperty + // a single aDescGet ( that *does* ) take params is basically a + // default method e.g. implement XDefaultMethod + + // a DescPut ( I guess we only really support a default param with '1' param ) as a setValue ( but I guess we can leave it through, the object will fail if we don't get it right anyway ) + if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) ) + m_bHasDfltProperty = true; + if ( aDescGet->cParams > 0 ) + m_bHasDfltMethod = true; + if ( m_bHasDfltProperty || m_bHasDfltMethod ) + m_sDefaultMember = usName; + } + } + catch ( BridgeRuntimeError & e ) + { + throw RuntimeException( e.message, Reference<XInterface>() ); + } + catch( Exception& e ) + { + throw RuntimeException( + OUSTR("[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n") + e.Message, + Reference<XInterface>() ); + } + } +} + +// -------------------------- +// XDirectInvocation +uno::Any SAL_CALL IUnknownWrapper_Impl::directInvoke( const ::rtl::OUString& aName, const uno::Sequence< uno::Any >& aParams ) + throw (lang::IllegalArgumentException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException) +{ + Any aResult; + + if ( !m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + + o2u_attachCurrentThread(); + DISPID dispid; + if ( !getDispid( aName, &dispid ) ) + throw IllegalArgumentException( + OUSTR( "[automation bridge] The object does not have a function or property " ) + + aName, Reference<XInterface>(), 0); + + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr = 0; + INVOKEKIND pInvkinds[2]; + pInvkinds[0] = INVOKE_FUNC; + pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET; + HRESULT hInvRes = E_FAIL; + + // try Invoke first, if it does not work, try put/get property + for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ ) + { + DISPPARAMS dispparams = {NULL, NULL, 0, 0}; + + DISPID idPropertyPut = DISPID_PROPERTYPUT; + scoped_array<DISPID> arDispidNamedArgs; + scoped_array<CComVariant> ptrArgs; + scoped_array<CComVariant> ptrRefArgs; // referenced arguments + CComVariant * arArgs = NULL; + CComVariant * arRefArgs = NULL; + bool bVarargParam = false; + + dispparams.cArgs = aParams.getLength(); + + // Determine the number of named arguments + for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ ) + if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0) ) + dispparams.cNamedArgs ++; + + // fill the named arguments + if ( dispparams.cNamedArgs > 0 + && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) ) + { + int nSizeAr = dispparams.cNamedArgs + 1; + if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT ) + nSizeAr = dispparams.cNamedArgs; + + scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]); + OLECHAR ** pNames = saNames.get(); + pNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(aName.getStr())); + + int cNamedArg = 0; + for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ ) + { + if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0)) + { + const NamedArgument& arg = *(NamedArgument const*)aParams[nInd].getValue(); + + //We put the parameter names in reverse order into the array, + //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs + //The first name in the array is the method name + pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr())); + } + } + + arDispidNamedArgs.reset( new DISPID[nSizeAr] ); + HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() ); + if ( hr == E_NOTIMPL ) + hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); + + if ( SUCCEEDED( hr ) ) + { + if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT ) + { + DISPID* arIDs = arDispidNamedArgs.get(); + arIDs[0] = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = arIDs; + } + else + { + DISPID* arIDs = arDispidNamedArgs.get(); + dispparams.rgdispidNamedArgs = & arIDs[1]; + } + } + else if (hr == DISP_E_UNKNOWNNAME) + { + throw IllegalArgumentException( + OUSTR("[automation bridge]One of the named arguments is wrong!"), + Reference<XInterface>(), 0); + } + else + { + throw InvocationTargetException( + OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ") + + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any()); + } + } + + //Convert arguments + ptrArgs.reset(new CComVariant[dispparams.cArgs]); + ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); + arArgs = ptrArgs.get(); + arRefArgs = ptrRefArgs.get(); + + sal_Int32 nInd = 0; + try + { + sal_Int32 revIndex = 0; + for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++) + { + revIndex = dispparams.cArgs - nInd - 1; + arRefArgs[revIndex].byref = 0; + Any anyArg; + if ( nInd < aParams.getLength() ) + anyArg = aParams.getConstArray()[nInd]; + + // Property Put arguments + if ( anyArg.getValueType() == getCppuType((PropertyPutArgument*)0) ) + { + PropertyPutArgument arg; + anyArg >>= arg; + anyArg <<= arg.Value; + } + // named argument + if (anyArg.getValueType() == getCppuType((NamedArgument*) 0)) + { + NamedArgument aNamedArgument; + anyArg >>= aNamedArgument; + anyArg <<= aNamedArgument.Value; + } + + if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID ) + { + anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT ); + } + else + { + arArgs[revIndex].vt = VT_ERROR; + arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = nInd; + throw; + } + + dispparams.rgvarg = arArgs; + // invoking OLE method + DWORD localeId = LOCALE_USER_DEFAULT; + hInvRes = m_spDispatch->Invoke( dispid, + IID_NULL, + localeId, + ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ), + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + } + + // converting return value and out parameter back to UNO + if ( SUCCEEDED( hInvRes ) ) + variantToAny( &varResult, aResult, sal_False ); + else + { + // map error codes to exceptions + OUString message; + switch ( hInvRes ) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException(OUSTR("[automation bridge] Wrong " + "number of arguments. Object returned DISP_E_BADPARAMCOUNT."), + 0, 0); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(OUSTR("[automation bridge] One or more " + "arguments have the wrong type. Object returned " + "DISP_E_BADVARTYPE."), 0); + break; + case DISP_E_EXCEPTION: + message = OUSTR("[automation bridge]: "); + message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription), + ::SysStringLen(excepinfo.bstrDescription)); + throw InvocationTargetException(message, Reference<XInterface>(), Any()); + break; + case DISP_E_MEMBERNOTFOUND: + message = OUSTR("[automation bridge]: A function with the name \"") + + aName + OUSTR("\" is not supported. Object returned " + "DISP_E_MEMBERNOTFOUND."); + throw IllegalArgumentException(message, 0, 0); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException(OUSTR("[automation bridge] Object " + "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")), + static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException(OUSTR("[automation bridge]Call failed." + "Object returned DISP_E_PARAMNOTFOUND."), + 0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_TYPEMISMATCH"), + static_cast<XInterface*>( + static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNINTERFACE."),0); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNLCID."),0); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException(OUSTR("[automation bridge] Call failed." + "Object returned DISP_E_PARAMNOTOPTIONAL"), + static_cast<XInterface*>(static_cast<XWeak*>(this)), + TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + } + + return aResult; +} + +::sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMember( const ::rtl::OUString& aName ) + throw (uno::RuntimeException) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + OUSTR("[automation bridge] The object does not have an IDispatch interface"), + Reference<XInterface>()); + } + + o2u_attachCurrentThread(); + DISPID dispid; + return getDispid( aName, &dispid ); +} + + +// UnoConversionUtilities -------------------------------------------------------------------------------- +Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance() +{ + if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) + { + Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); + } + else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) + { + Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); + } + else + return Reference<XInterface>(); +} +Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance() +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + + + +void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo) +{ + TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); + if( desc.is()) + { + typelib_TypeDescription* pMember= desc.get(); + if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD ) + methodInfo= pMember; + } +} + +void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo) +{ + TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); + if( desc.is()) + { + typelib_TypeDescription* pMember= desc.get(); + if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE ) + { + attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef; + } + } +} +TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName) +{ + TypeDescription ret; + + for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++) + { + TypeDescription _curDesc( m_seqTypes[i]); + _curDesc.makeComplete(); + typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get(); + if( pInterface) + { + typelib_InterfaceMemberTypeDescription* pMember= NULL; + //find the member description of the current call + for( int i=0; i < pInterface->nAllMembers; i++) + { + typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i]; + typelib_TypeDescription* pDescMember= NULL; + TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember) + + typelib_InterfaceMemberTypeDescription* pInterfaceMember= + (typelib_InterfaceMemberTypeDescription*) pDescMember; + if( OUString( pInterfaceMember->pMemberName) == sName) + { + pMember= pInterfaceMember; + break; + } + TYPELIB_DANGER_RELEASE( pDescMember) + } + + if( pMember) + { + ret= (typelib_TypeDescription*)pMember; + TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember); + } + } + if( ret.is()) + break; + } + return ret; +} + +sal_Bool IUnknownWrapper_Impl::isJScriptObject() +{ + if( m_eJScript == JScriptUndefined) + { + CComDispatchDriver disp( m_spDispatch); + if( disp) + { + CComVariant result; + if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result))) + { + if(result.vt == VT_BSTR) + { + CComBSTR name( result.bstrVal); + name.ToLower(); + if( name == CComBSTR(JSCRIPT_ID)) + m_eJScript= IsJScript; + } + } + } + if( m_eJScript == JScriptUndefined) + m_eJScript= NoJScript; + } + + return m_eJScript == NoJScript ? sal_False : sal_True; +} + + + +/** @internal + The function ultimately calls IDispatch::Invoke on the wrapped COM object. + The COM object does not implement UNO Interfaces ( via IDispatch). This + is the case when the OleObjectFactory service has been used to create a + component. + @exception IllegalArgumentException + @exception CannotConvertException + @InvocationTargetException + @RuntimeException + @BridgeRuntimeError +*/ +Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam) +{ + Any ret; + HRESULT result; + + DISPPARAMS dispparams = {NULL, NULL, 0, 0}; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + sal_Int32 i = 0; + sal_Int32 nUnoArgs = Params.getLength(); + DISPID idPropertyPut = DISPID_PROPERTYPUT; + scoped_array<DISPID> arDispidNamedArgs; + scoped_array<CComVariant> ptrArgs; + scoped_array<CComVariant> ptrRefArgs; // referenced arguments + CComVariant * arArgs = NULL; + CComVariant * arRefArgs = NULL; + sal_Int32 revIndex = 0; + bool bVarargParam = false; + + // Get type info for the call. It can be a method call or property put or + // property get operation. + FuncDesc aFuncDesc(getTypeInfo()); + getFuncDescForInvoke(sFuncName, Params, & aFuncDesc); + + //Set the array of DISPIDs for named args if it is a property put operation. + //If there are other named arguments another array is set later on. + if (aFuncDesc->invkind == INVOKE_PROPERTYPUT + || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + dispparams.rgdispidNamedArgs = & idPropertyPut; + + //Determine the number of named arguments + for (int iParam = 0; iParam < nUnoArgs; iParam ++) + { + const Any & curArg = Params[iParam]; + if (curArg.getValueType() == getCppuType((NamedArgument*) 0)) + dispparams.cNamedArgs ++; + } + //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT). + //Therefore the number of named arguments is increased by one. + //Although named, the argument is not named in a actual language, such as Basic, + //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument + if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT + || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) + dispparams.cNamedArgs ++; + + //Determine the number of all arguments and named arguments + if (aFuncDesc->cParamsOpt == -1) + { + //Attribute vararg is set on this method. "Unlimited" number of args + //supported. There can be no optional or defaultvalue on any of the arguments. + dispparams.cArgs = nUnoArgs; + } + else + { + //If there are namesd arguments, then the dispparams.cArgs + //is the number of supplied args, otherwise it is the expected number. + if (dispparams.cNamedArgs) + dispparams.cArgs = nUnoArgs; + else + dispparams.cArgs = aFuncDesc->cParams; + } + + //check if there are not to many arguments supplied + if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs) + { + OUStringBuffer buf(256); + buf.appendAscii("[automation bridge] There are too many arguments for this method"); + throw IllegalArgumentException( buf.makeStringAndClear(), + Reference<XInterface>(), (sal_Int16) dispparams.cArgs); + } + + //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs) + //for the named arguments. + //If there is only one named arg and if it is because of a property put + //operation, then we need not set up the DISPID array. + if (dispparams.cNamedArgs > 0 && + ! (dispparams.cNamedArgs == 1 && + (aFuncDesc->invkind == INVOKE_PROPERTYPUT || + aFuncDesc->invkind == INVOKE_PROPERTYPUT))) + { + //set up an array containing the member and parameter names + //which is then used in ITypeInfo::GetIDsOfNames + //First determine the size of the array of names which is passed to + //ITypeInfo::GetIDsOfNames. It must hold the method names + the named + //args. + int nSizeAr = dispparams.cNamedArgs + 1; + if (aFuncDesc->invkind == INVOKE_PROPERTYPUT + || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + { + nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT + } + + scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]); + OLECHAR ** arNames = saNames.get(); + arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr())); + + int cNamedArg = 0; + for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++) + { + const Any & curArg = Params[iParams]; + if (curArg.getValueType() == getCppuType((NamedArgument*) 0)) + { + const NamedArgument& arg = *(NamedArgument const*) curArg.getValue(); + //We put the parameter names in reverse order into the array, + //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs + //The first name in the array is the method name + arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr())); + } + } + + //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames + //it must be big enough to contain the DISPIDs of the member + parameters + arDispidNamedArgs.reset(new DISPID[nSizeAr]); + HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr, + arDispidNamedArgs.get()); + if ( hr == E_NOTIMPL ) + hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); + + if (hr == S_OK) + { + // In a "property put" operation, the property value is a named param with the + //special DISPID DISPID_PROPERTYPUT + if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT + || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) + { + //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT + //The first item in the array arDispidNamedArgs is the DISPID for + //the method. We replace it with DISPID_PROPERTYPUT. + DISPID* arIDs = arDispidNamedArgs.get(); + arIDs[0] = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = arIDs; + } + else + { + //The first item in the array arDispidNamedArgs is the DISPID for + //the method. It must be removed + DISPID* arIDs = arDispidNamedArgs.get(); + dispparams.rgdispidNamedArgs = & arIDs[1]; + } + } + else if (hr == DISP_E_UNKNOWNNAME) + { + throw IllegalArgumentException( + OUSTR("[automation bridge]One of the named arguments is wrong!"), + Reference<XInterface>(), 0); + } + else + { + throw InvocationTargetException( + OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ") + + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any()); + } + } + + //Convert arguments + ptrArgs.reset(new CComVariant[dispparams.cArgs]); + ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); + arArgs = ptrArgs.get(); + arRefArgs = ptrRefArgs.get(); + try + { + for (i = 0; i < (sal_Int32) dispparams.cArgs; i++) + { + revIndex= dispparams.cArgs - i -1; + arRefArgs[revIndex].byref=0; + Any anyArg; + if ( i < nUnoArgs) + anyArg= Params.getConstArray()[i]; + + //Test if the current parameter is a "vararg" parameter. + if (bVarargParam || (aFuncDesc->cParamsOpt == -1 && + aFuncDesc->cParams == (i + 1))) + { //This parameter is from the variable argument list. There is no + //type info available, except that it must be a VARIANT + bVarargParam = true; + } + + unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN; + VARTYPE varType = VT_VARIANT; + if ( ! bVarargParam) + { + paramFlags = + aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags; + varType = getElementTypeDesc( + & aFuncDesc->lprgelemdescParam[i].tdesc); + } + //Make sure that there is a UNO parameter for every + // expected parameter. If there is no UNO parameter where the + // called function expects one, then it must be optional. Otherwise + // its a UNO programming error. + if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT)) + { + OUStringBuffer buf(256); + buf.appendAscii("ole automation bridge: The called function expects an argument at" + "position: "); //a different number of arguments")), + buf.append(OUString::valueOf((sal_Int32) i)); + buf.appendAscii(" (index starting at 0)."); + throw IllegalArgumentException( buf.makeStringAndClear(), + Reference<XInterface>(), (sal_Int16) i); + } + + // Property Put arguments + if (anyArg.getValueType() == getCppuType((PropertyPutArgument*)0)) + { + PropertyPutArgument arg; + anyArg >>= arg; + anyArg <<= arg.Value; + } + // named argument + if (anyArg.getValueType() == getCppuType((NamedArgument*) 0)) + { + NamedArgument aNamedArgument; + anyArg >>= aNamedArgument; + anyArg <<= aNamedArgument.Value; + } + // out param + if (paramFlags & PARAMFLAG_FOUT && + ! (paramFlags & PARAMFLAG_FIN) ) + { + VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); + if (i < nUnoArgs) + { + arRefArgs[revIndex].vt= type; + } + else + { + //optional arg + arRefArgs[revIndex].vt = VT_ERROR; + arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + if( type == VT_VARIANT ) + { + arArgs[revIndex].vt= VT_VARIANT | VT_BYREF; + arArgs[revIndex].byref= &arRefArgs[revIndex]; + } + else + { + arArgs[revIndex].vt= varType; + if (type == VT_DECIMAL) + arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; + else + arArgs[revIndex].byref= & arRefArgs[revIndex].byref; + } + } + // in/out + in byref params + else if (varType & VT_BYREF) + { + VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); + CComVariant var; + + if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) + { + anyToVariant( & arRefArgs[revIndex], anyArg, type); + } + else if (paramFlags & PARAMFLAG_FHASDEFAULT) + { + //optional arg with default + VariantCopy( & arRefArgs[revIndex], + & aFuncDesc->lprgelemdescParam[i].paramdesc. + pparamdescex->varDefaultValue); + } + else + { + //optional arg + //e.g: call func(x) in basic : func() ' no arg supplied + OSL_ASSERT(paramFlags & PARAMFLAG_FOPT); + arRefArgs[revIndex].vt = VT_ERROR; + arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + + // Set the converted arguments in the array which will be + // DISPPARAMS::rgvarg + // byref arg VT_XXX |VT_BYREF + arArgs[revIndex].vt = varType; + if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT) + { + arArgs[revIndex] = arRefArgs[revIndex]; + } + else if (type == VT_DECIMAL) + { + arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; + } + else if (type == VT_VARIANT) + { + if ( ! (paramFlags & PARAMFLAG_FOUT)) + arArgs[revIndex] = arRefArgs[revIndex]; + else + arArgs[revIndex].byref = & arRefArgs[revIndex]; + } + else + { + arArgs[revIndex].byref = & arRefArgs[revIndex].byref; + arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF ); + } + + } + // in parameter no VT_BYREF except for array, interfaces + else + { // void any stands for optional param + if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) + { + anyToVariant( & arArgs[revIndex], anyArg, varType); + } + //optional arg but no void any supplied + //Basic: obj.func() ' first parameter left out because it is optional + else if (paramFlags & PARAMFLAG_FHASDEFAULT) + { + //optional arg with defaulteithter as direct arg : VT_XXX or + VariantCopy( & arArgs[revIndex], + & aFuncDesc->lprgelemdescParam[i].paramdesc. + pparamdescex->varDefaultValue); + } + else if (paramFlags & PARAMFLAG_FOPT) + { + arArgs[revIndex].vt = VT_ERROR; + arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + else + { + arArgs[revIndex].vt = VT_EMPTY; + arArgs[revIndex].lVal = 0; + } + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + dispparams.rgvarg= arArgs; + // invoking OLE method + DWORD localeId = LOCALE_USER_DEFAULT; + result = m_spDispatch->Invoke(aFuncDesc->memid, + IID_NULL, + localeId, + ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ), + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (result == S_OK) + { + + // allocate space for the out param Sequence and indices Sequence + int outParamsCount= 0; // includes in/out parameter + for (int i = 0; i < aFuncDesc->cParams; i++) + { + if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags & + PARAMFLAG_FOUT) + outParamsCount++; + } + + OutParamIndex.realloc(outParamsCount); + OutParam.realloc(outParamsCount); + // Convert out params + if (outParamsCount) + { + int outParamIndex=0; + for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++) + { + //Determine the index within the method sinature + int realParamIndex = paramIndex; + int revParamIndex = dispparams.cArgs - paramIndex - 1; + if (Params[paramIndex].getValueType() + == getCppuType((NamedArgument*) 0)) + { + //dispparams.rgdispidNamedArgs contains the mapping from index + //of named args list to index of parameter list + realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex]; + } + + // no named arg, always come before named args + if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags + & PARAMFLAG_FOUT)) + continue; + Any outAny; + // variantToAny is called with the "reduce range" parameter set to sal_False. + // That causes VT_I4 values not to be converted down to a "lower" type. That + // feature exist for JScript only because it only uses VT_I4 for integer types. + try + { + variantToAny( & arRefArgs[revParamIndex], outAny, sal_False ); + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = (sal_Int16)paramIndex; + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = paramIndex; + throw; + } + OutParam[outParamIndex] = outAny; + OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex ); + outParamIndex++; + } + OutParam.realloc(outParamIndex); + OutParamIndex.realloc(outParamIndex); + } + // Return value + variantToAny(&varResult, ret, sal_False); + } + + // map error codes to exceptions + OUString message; + switch (result) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException(OUSTR("[automation bridge] Wrong " + "number of arguments. Object returned DISP_E_BADPARAMCOUNT."), + 0, 0); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(OUSTR("[automation bridge] One or more " + "arguments have the wrong type. Object returned " + "DISP_E_BADVARTYPE."), 0); + break; + case DISP_E_EXCEPTION: + message = OUSTR("[automation bridge]: "); + message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription), + ::SysStringLen(excepinfo.bstrDescription)); + throw InvocationTargetException(message, Reference<XInterface>(), Any()); + break; + case DISP_E_MEMBERNOTFOUND: + message = OUSTR("[automation bridge]: A function with the name \"") + + sFuncName + OUSTR("\" is not supported. Object returned " + "DISP_E_MEMBERNOTFOUND."); + throw IllegalArgumentException(message, 0, 0); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException(OUSTR("[automation bridge] Object " + "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")), + static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException(OUSTR("[automation bridge]Call failed." + "Object returned DISP_E_PARAMNOTFOUND."), + 0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_TYPEMISMATCH"), + static_cast<XInterface*>( + static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNINTERFACE."),0); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(OUSTR("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNLCID."),0); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException(OUSTR("[automation bridge] Call failed." + "Object returned DISP_E_PARAMNOTOPTIONAL"), + static_cast<XInterface*>(static_cast<XWeak*>(this)), + TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + + return ret; +} + +void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName, + const Sequence<Any> & seqArgs, + FUNCDESC** pFuncDesc) +{ + int nUnoArgs = seqArgs.getLength(); + const Any * arArgs = seqArgs.getConstArray(); + ITypeInfo* pInfo = getTypeInfo(); + + //If the last of the positional arguments is a PropertyPutArgument + //then obtain the type info for the property put operation. + + //The property value is always the last argument, in a positional argument list + //or in a list of named arguments. A PropertyPutArgument is actually a named argument + //hence it must not be put in an extra NamedArgument structure + if (nUnoArgs > 0 && + arArgs[nUnoArgs - 1].getValueType() == getCppuType((PropertyPutArgument*) 0)) + { + // DISPATCH_PROPERTYPUT + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc); + if ( ! aDescPut) + { + throw IllegalArgumentException( + OUSTR("[automation bridge] The object does not have a writeable property: ") + + sFuncName, Reference<XInterface>(), 0); + } + *pFuncDesc = aDescPut.Detach(); + } + else + { // DISPATCH_METHOD + FuncDesc aFuncDesc(pInfo); + getFuncDesc(sFuncName, & aFuncDesc); + if ( ! aFuncDesc) + { + // Fallback: DISPATCH_PROPERTYGET can mostly be called as + // DISPATCH_METHOD + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc); + if ( ! aFuncDesc ) + { + throw IllegalArgumentException( + OUSTR("[automation bridge] The object does not have a function" + "or readable property \"") + + sFuncName, Reference<XInterface>(), 0); + } + } + *pFuncDesc = aFuncDesc.Detach(); + } +} +bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id) +{ + OSL_ASSERT(m_spDispatch); + LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr())); + HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id); + return hr == S_OK ? true : false; +} +void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc) + +{ + OSL_ASSERT( * pFuncDesc == 0); + buildComTlbIndex(); + typedef TLBFuncIndexMap::const_iterator cit; + typedef TLBFuncIndexMap::iterator it; + //We assume there is only one entry with the function name. A property + //would have two entries. + cit itIndex= m_mapComFunc.find(sFuncName); + if (itIndex == m_mapComFunc.end()) + { + //try case insensive with IDispatch::GetIDsOfNames + DISPID id; + if (getDispid(sFuncName, &id)) + { + CComBSTR memberName; + unsigned int pcNames=0; + // get the case sensitive name + if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) + { + //get the associated index and add an entry to the map + //with the name sFuncName which differs in the casing of the letters to + //the actual name as obtained from ITypeInfo + cit itOrg = m_mapComFunc.find(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)))); + OSL_ASSERT(itOrg != m_mapComFunc.end()); + itIndex = + m_mapComFunc.insert( TLBFuncIndexMap::value_type + ( make_pair(sFuncName, itOrg->second ) )); + } + } + } + +#if OSL_DEBUG_LEVEL >= 1 + // There must only be one entry if sFuncName represents a function or two + // if it is a property + pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase()); + int numEntries = 0; + for ( ;p.first != p.second; p.first ++, numEntries ++); + OSL_ASSERT( ! (numEntries > 3) ); +#endif + if( itIndex != m_mapComFunc.end()) + { + ITypeInfo* pType= getTypeInfo(); + FUNCDESC * pDesc = NULL; + if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc))) + { + if (pDesc->invkind == INVOKE_FUNC) + { + (*pFuncDesc) = pDesc; + } + else + { + pType->ReleaseFuncDesc(pDesc); + } + } + else + { + throw BridgeRuntimeError(OUSTR("[automation bridge] Could not get " + "FUNCDESC for ") + sFuncName); + } + } + //else no entry found for sFuncName, pFuncDesc will not be filled in +} + +void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet, + FUNCDESC** pFuncDescPut, VARDESC** pVarDesc) +{ + OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0); + buildComTlbIndex(); + typedef TLBFuncIndexMap::const_iterator cit; + pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName); + if (p.first == m_mapComFunc.end()) + { + //try case insensive with IDispatch::GetIDsOfNames + DISPID id; + if (getDispid(sFuncName, &id)) + { + CComBSTR memberName; + unsigned int pcNames=0; + // get the case sensitive name + if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) + { + //As opposed to getFuncDesc, we do not add the value because we would + // need to find the get and set description for the property. This would + //mean to iterate over all FUNCDESCs again. + p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)))); + } + } + } + + for ( int i = 0 ;p.first != p.second; p.first ++, i ++) + { + // There are a maximum of two entries, property put and property get + OSL_ASSERT( ! (i > 2) ); + ITypeInfo* pType= getTypeInfo(); + FUNCDESC * pFuncDesc = NULL; + if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc))) + { + if (pFuncDesc->invkind == INVOKE_PROPERTYGET) + { + (*pFuncDescGet) = pFuncDesc; + } + else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT || + pFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + { + //a property can have 3 entries, put, put ref, get + // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used + //depends on what is found first. + if ( * pFuncDescPut) + { + //we already have found one + pType->ReleaseFuncDesc(pFuncDesc); + } + else + { + (*pFuncDescPut) = pFuncDesc; + } + } + else + { + pType->ReleaseFuncDesc(pFuncDesc); + } + } + //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC + // with invkind = INVOKE_FUNC. Since this function should only return + //a value for a real property (XInvokation::hasMethod, ..::hasProperty + //we need to make sure that sFuncName represents a real property. + VARDESC * pVD = NULL; + if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD))) + (*pVarDesc) = pVD; + } + //else no entry for sFuncName, pFuncDesc will not be filled in +} + +VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc) +{ + VARTYPE _type( VT_NULL ); + + if (desc->vt == VT_PTR) + { + _type = getElementTypeDesc(desc->lptdesc); + _type |= VT_BYREF; + } + else if (desc->vt == VT_SAFEARRAY) + { + _type = getElementTypeDesc(desc->lptdesc); + _type |= VT_ARRAY; + } + else if (desc->vt == VT_USERDEFINED) + { + ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance + CComPtr<ITypeInfo> spRefInfo; + thisInfo->GetRefTypeInfo(desc->hreftype, & spRefInfo.p); + if (spRefInfo) + { + TypeAttr attr(spRefInfo); + spRefInfo->GetTypeAttr( & attr); + if (attr->typekind == TKIND_ENUM) + { + //We use the type of the first enum value. + if (attr->cVars == 0) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] Could " + "not obtain type description")); + } + VarDesc var(spRefInfo); + spRefInfo->GetVarDesc(0, & var); + _type = var->lpvarValue->vt; + } + else if (attr->typekind == TKIND_INTERFACE) + { + _type = VT_UNKNOWN; + } + else if (attr->typekind == TKIND_DISPATCH) + { + _type = VT_DISPATCH; + } + else + { + throw BridgeRuntimeError(OUSTR("[automation bridge] " + "Unhandled user defined type.")); + } + } + } + else + { + _type = desc->vt; + } + return _type; +} + +void IUnknownWrapper_Impl::buildComTlbIndex() +{ + if ( ! m_bComTlbIndexInit) + { + MutexGuard guard(getBridgeMutex()); + { + if ( ! m_bComTlbIndexInit) + { + OUString sError; + ITypeInfo* pType= getTypeInfo(); + TypeAttr typeAttr(pType); + if( SUCCEEDED( pType->GetTypeAttr( &typeAttr))) + { + for( long i= 0; i < typeAttr->cFuncs; i++) + { + FuncDesc funcDesc(pType); + if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc))) + { + CComBSTR memberName; + unsigned int pcNames=0; + if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames))) + { + OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))); + m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i)); + } + else + { + sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \ + "ITypeInfo::GetNames failed."); + } + } + else + sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \ + "ITypeInfo::GetFuncDesc failed."); + } + + //If we create an Object in JScript and a a property then it + //has VARDESC instead of FUNCDESC + for (long i = 0; i < typeAttr->cVars; i++) + { + VarDesc varDesc(pType); + if (SUCCEEDED(pType->GetVarDesc(i, & varDesc))) + { + CComBSTR memberName; + unsigned int pcNames = 0; + if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames))) + { + if (varDesc->varkind == VAR_DISPATCH) + { + OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))); + m_mapComFunc.insert(TLBFuncIndexMap::value_type( + usName, i)); + } + } + else + { + sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \ + "ITypeInfo::GetNames failed."); + } + } + else + sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \ + "ITypeInfo::GetVarDesc failed."); + + } + } + else + sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \ + "ITypeInfo::GetTypeAttr failed."); + + if (sError.getLength()) + { + throw BridgeRuntimeError(sError); + } + + m_bComTlbIndexInit = true; + } + } + } +} + +ITypeInfo* IUnknownWrapper_Impl::getTypeInfo() +{ + if( !m_spDispatch) + { + throw BridgeRuntimeError(OUSTR("The object has no IDispatch interface!")); + } + + if( !m_spTypeInfo ) + { + MutexGuard guard(getBridgeMutex()); + if( ! m_spTypeInfo) + { + CComPtr< ITypeInfo > spType; + if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p))) + + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + + //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE + //We need to get the type description for TKIND_DISPATCH + TypeAttr typeAttr(spType.p); + if( SUCCEEDED(spType->GetTypeAttr( &typeAttr))) + { + if (typeAttr->typekind == TKIND_INTERFACE && + typeAttr->wTypeFlags & TYPEFLAG_FDUAL) + { + HREFTYPE refDispatch; + if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch))) + { + CComPtr<ITypeInfo> spTypeDisp; + if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp))) + m_spTypeInfo= spTypeDisp; + } + else + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] Could not obtain type information " + "for dispatch interface." )); + } + } + else if (typeAttr->typekind == TKIND_DISPATCH) + { + m_spTypeInfo= spType; + } + else + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] Automation object does not " + "provide type information.")); + } + } + } + else + { + throw BridgeRuntimeError(OUSTR("[automation bridge]The dispatch object does not " + "support ITypeInfo!")); + } + } + } + return m_spTypeInfo; +} + +} // end namespace + |