| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 lcl_getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ) |
| { |
| VARTYPE _type( VT_NULL ); |
| if ( pTypeInfo ) |
| { |
| CComPtr<ITypeInfo> spRefInfo; |
| pTypeInfo->GetRefTypeInfo( nHrefType, &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 if ( attr->typekind == TKIND_ALIAS ) |
| { |
| // TKIND_ALIAS is a type that is an alias for another type. So get that alias type. |
| _type = lcl_getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype ); |
| } |
| else |
| { |
| throw BridgeRuntimeError( OUSTR("[automation bridge] Unhandled user defined type.") ); |
| } |
| } |
| } |
| return _type; |
| } |
| |
| 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 |
| _type = lcl_getUserDefinedElementType( thisInfo, desc->hreftype ); |
| } |
| 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 |
| |