| /************************************************************** |
| * |
| * 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_stoc.hxx" |
| |
| #include <hash_map> |
| #include <hash_set> |
| |
| #include <osl/diagnose.h> |
| #include <osl/interlck.h> |
| #include <osl/mutex.hxx> |
| |
| #include <uno/dispatcher.h> |
| #include <uno/data.h> |
| #include <uno/any2.h> |
| #include <uno/mapping.hxx> |
| |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/implbase3.hxx> |
| #include <cppuhelper/implementationentry.hxx> |
| |
| #include <com/sun/star/uno/XAggregation.hpp> |
| #include <com/sun/star/script/XTypeConverter.hpp> |
| #include <com/sun/star/script/XInvocationAdapterFactory.hpp> |
| #include <com/sun/star/script/XInvocationAdapterFactory2.hpp> |
| #include <com/sun/star/script/XInvocation.hpp> |
| #include <com/sun/star/lang/XServiceInfo.hpp> |
| #include <com/sun/star/lang/XSingleServiceFactory.hpp> |
| #include <com/sun/star/registry/XSimpleRegistry.hpp> |
| #include <com/sun/star/registry/XRegistryKey.hpp> |
| #include <com/sun/star/reflection/InvocationTargetException.hpp> |
| #include "com/sun/star/uno/RuntimeException.hpp" |
| |
| #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) |
| |
| #define SERVICENAME "com.sun.star.script.InvocationAdapterFactory" |
| #define IMPLNAME "com.sun.star.comp.stoc.InvocationAdapterFactory" |
| |
| |
| using namespace ::std; |
| using namespace ::rtl; |
| using namespace ::osl; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| namespace stoc_invadp |
| { |
| |
| static rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; |
| |
| static Sequence< OUString > invadp_getSupportedServiceNames() |
| { |
| static Sequence < OUString > *pNames = 0; |
| if( ! pNames ) |
| { |
| MutexGuard guard( Mutex::getGlobalMutex() ); |
| if( !pNames ) |
| { |
| static Sequence< OUString > seqNames(1); |
| seqNames.getArray()[0] = |
| OUString(RTL_CONSTASCII_USTRINGPARAM(SERVICENAME)); |
| pNames = &seqNames; |
| } |
| } |
| return *pNames; |
| } |
| |
| static OUString invadp_getImplementationName() |
| { |
| static OUString *pImplName = 0; |
| if( ! pImplName ) |
| { |
| MutexGuard guard( Mutex::getGlobalMutex() ); |
| if( ! pImplName ) |
| { |
| static OUString implName( RTL_CONSTASCII_USTRINGPARAM( IMPLNAME ) ); |
| pImplName = &implName; |
| } |
| } |
| return *pImplName; |
| } |
| |
| struct hash_ptr |
| { |
| inline size_t operator() ( void * p ) const |
| { return (size_t)p; } |
| }; |
| typedef hash_set< void *, hash_ptr, equal_to< void * > > t_ptr_set; |
| typedef hash_map< void *, t_ptr_set, hash_ptr, equal_to< void * > > t_ptr_map; |
| |
| //============================================================================== |
| class FactoryImpl |
| : public ::cppu::WeakImplHelper3< lang::XServiceInfo, |
| script::XInvocationAdapterFactory, |
| script::XInvocationAdapterFactory2 > |
| { |
| public: |
| Mapping m_aUno2Cpp; |
| Mapping m_aCpp2Uno; |
| uno_Interface * m_pConverter; |
| |
| typelib_TypeDescription * m_pInvokMethodTD; |
| typelib_TypeDescription * m_pSetValueTD; |
| typelib_TypeDescription * m_pGetValueTD; |
| typelib_TypeDescription * m_pAnySeqTD; |
| typelib_TypeDescription * m_pShortSeqTD; |
| typelib_TypeDescription * m_pConvertToTD; |
| |
| Mutex m_mutex; |
| t_ptr_map m_receiver2adapters; |
| |
| FactoryImpl( Reference< XComponentContext > const & xContext ) |
| SAL_THROW( (RuntimeException) ); |
| virtual ~FactoryImpl() SAL_THROW( () ); |
| |
| // XServiceInfo |
| virtual OUString SAL_CALL getImplementationName() |
| throw (RuntimeException); |
| virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) |
| throw (RuntimeException); |
| virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() |
| throw (RuntimeException); |
| |
| // XInvocationAdapterFactory |
| virtual Reference< XInterface > SAL_CALL createAdapter( |
| const Reference< script::XInvocation > & xReceiver, const Type & rType ) |
| throw (RuntimeException); |
| // XInvocationAdapterFactory2 |
| virtual Reference< XInterface > SAL_CALL createAdapter( |
| const Reference< script::XInvocation > & xReceiver, |
| const Sequence< Type > & rTypes ) |
| throw (RuntimeException); |
| }; |
| struct AdapterImpl; |
| //============================================================================== |
| struct InterfaceAdapterImpl : public uno_Interface |
| { |
| AdapterImpl * m_pAdapter; |
| typelib_InterfaceTypeDescription * m_pTypeDescr; |
| }; |
| //============================================================================== |
| struct AdapterImpl |
| { |
| oslInterlockedCount m_nRef; |
| FactoryImpl * m_pFactory; |
| void * m_key; // map key |
| uno_Interface * m_pReceiver; // XInvocation receiver |
| |
| sal_Int32 m_nInterfaces; |
| InterfaceAdapterImpl * m_pInterfaces; |
| |
| // XInvocation calls |
| void getValue( |
| const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * pArgs[], uno_Any ** ppException ); |
| void setValue( |
| const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * pArgs[], uno_Any ** ppException ); |
| void invoke( |
| const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * pArgs[], uno_Any ** ppException ); |
| |
| bool coerce_assign( |
| void * pDest, typelib_TypeDescriptionReference * pType, |
| uno_Any * pSource, uno_Any * pExc ); |
| inline bool coerce_construct( |
| void * pDest, typelib_TypeDescriptionReference * pType, |
| uno_Any * pSource, uno_Any * pExc ); |
| |
| inline void acquire() |
| SAL_THROW( () ); |
| inline void release() |
| SAL_THROW( () ); |
| inline ~AdapterImpl() |
| SAL_THROW( () ); |
| inline AdapterImpl( |
| void * key, Reference< script::XInvocation > const & xReceiver, |
| const Sequence< Type > & rTypes, |
| FactoryImpl * pFactory ) |
| SAL_THROW( (RuntimeException) ); |
| }; |
| //______________________________________________________________________________ |
| inline AdapterImpl::~AdapterImpl() |
| SAL_THROW( () ) |
| { |
| for ( sal_Int32 nPos = m_nInterfaces; nPos--; ) |
| { |
| ::typelib_typedescription_release( |
| (typelib_TypeDescription *)m_pInterfaces[ nPos ].m_pTypeDescr ); |
| } |
| delete [] m_pInterfaces; |
| // |
| (*m_pReceiver->release)( m_pReceiver ); |
| m_pFactory->release(); |
| } |
| //______________________________________________________________________________ |
| inline void AdapterImpl::acquire() |
| SAL_THROW( () ) |
| { |
| ::osl_incrementInterlockedCount( &m_nRef ); |
| } |
| //______________________________________________________________________________ |
| inline void AdapterImpl::release() |
| SAL_THROW( () ) |
| { |
| bool delete_this = false; |
| { |
| MutexGuard guard( m_pFactory->m_mutex ); |
| if (! ::osl_decrementInterlockedCount( &m_nRef )) |
| { |
| t_ptr_map::iterator iFind( |
| m_pFactory->m_receiver2adapters.find( m_key ) ); |
| OSL_ASSERT( m_pFactory->m_receiver2adapters.end() != iFind ); |
| t_ptr_set & adapter_set = iFind->second; |
| if (adapter_set.erase( this ) != 1) { |
| OSL_ASSERT( false ); |
| } |
| if (adapter_set.empty()) |
| { |
| m_pFactory->m_receiver2adapters.erase( iFind ); |
| } |
| delete_this = true; |
| } |
| } |
| if (delete_this) |
| delete this; |
| } |
| |
| //------------------------------------------------------------------------------ |
| static inline void constructRuntimeException( |
| uno_Any * pExc, const OUString & rMsg ) |
| { |
| RuntimeException exc( rMsg, Reference< XInterface >() ); |
| // no conversion neeeded due to binary compatibility + no convertable type |
| ::uno_type_any_construct( |
| pExc, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| static inline sal_Bool type_equals( |
| typelib_TypeDescriptionReference * pType1, |
| typelib_TypeDescriptionReference * pType2 ) |
| SAL_THROW( () ) |
| { |
| return (pType1 == pType2 || |
| (pType1->pTypeName->length == pType2->pTypeName->length && |
| 0 == ::rtl_ustr_compare( |
| pType1->pTypeName->buffer, pType2->pTypeName->buffer ))); |
| } |
| |
| //______________________________________________________________________________ |
| bool AdapterImpl::coerce_assign( |
| void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource, |
| uno_Any * pOutExc ) |
| { |
| if (typelib_TypeClass_ANY == pType->eTypeClass) |
| { |
| ::uno_type_any_assign( |
| (uno_Any *)pDest, pSource->pData, pSource->pType, 0, 0 ); |
| return true; |
| } |
| if (::uno_type_assignData( |
| pDest, pType, pSource->pData, pSource->pType, 0, 0, 0 )) |
| { |
| return true; |
| } |
| else // try type converter |
| { |
| uno_Any ret; |
| void * args[ 2 ]; |
| args[ 0 ] = pSource; |
| args[ 1 ] = &pType; |
| uno_Any exc; |
| uno_Any * p_exc = &exc; |
| |
| // converTo() |
| (*m_pFactory->m_pConverter->pDispatcher)( |
| m_pFactory->m_pConverter, |
| m_pFactory->m_pConvertToTD, &ret, args, &p_exc ); |
| |
| if (p_exc) // exception occured |
| { |
| OSL_ASSERT( |
| p_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION ); |
| if (typelib_typedescriptionreference_isAssignableFrom( |
| ::getCppuType( |
| (RuntimeException const *) 0 ).getTypeLibType(), |
| p_exc->pType )) |
| { |
| // is RuntimeException or derived: rethrow |
| uno_type_any_construct( |
| pOutExc, p_exc->pData, p_exc->pType, 0 ); |
| } |
| else |
| { |
| // set runtime exception |
| constructRuntimeException( |
| pOutExc, OUSTR("type coercion failed: ") + |
| reinterpret_cast< Exception const * >( |
| p_exc->pData )->Message ); |
| } |
| ::uno_any_destruct( p_exc, 0 ); |
| // pOutExc constructed |
| return false; |
| } |
| else |
| { |
| bool succ = (sal_False != ::uno_type_assignData( |
| pDest, pType, ret.pData, ret.pType, 0, 0, 0 )); |
| ::uno_any_destruct( &ret, 0 ); |
| OSL_ENSURE( |
| succ, "### conversion succeeded, but assignment failed!?" ); |
| if (! succ) |
| { |
| // set runtime exception |
| constructRuntimeException( |
| pOutExc, |
| OUSTR("type coercion failed: " |
| "conversion succeeded, but assignment failed?!") ); |
| } |
| return succ; |
| } |
| } |
| } |
| //______________________________________________________________________________ |
| inline bool AdapterImpl::coerce_construct( |
| void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource, |
| uno_Any * pExc ) |
| { |
| if (typelib_TypeClass_ANY == pType->eTypeClass) |
| { |
| ::uno_type_copyData( pDest, pSource, pType, 0 ); |
| return true; |
| } |
| if (type_equals( pType, pSource->pType)) |
| { |
| ::uno_type_copyData( pDest, pSource->pData, pType, 0 ); |
| return true; |
| } |
| ::uno_type_constructData( pDest, pType ); |
| return coerce_assign( pDest, pType, pSource, pExc ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| static void handleInvokExc( uno_Any * pDest, uno_Any * pSource ) |
| { |
| OUString const & name = |
| *reinterpret_cast< OUString const * >( &pSource->pType->pTypeName ); |
| |
| if (name.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM( |
| "com.sun.star.reflection.InvocationTargetException") )) |
| { |
| // unwrap invocation target exception |
| uno_Any * target_exc = |
| &reinterpret_cast< reflection::InvocationTargetException * >( |
| pSource->pData )->TargetException; |
| ::uno_type_any_construct( |
| pDest, target_exc->pData, target_exc->pType, 0 ); |
| } |
| else // all other exceptions are wrapped to RuntimeException |
| { |
| if (typelib_TypeClass_EXCEPTION == pSource->pType->eTypeClass) |
| { |
| constructRuntimeException( |
| pDest, ((Exception const *)pSource->pData)->Message ); |
| } |
| else |
| { |
| constructRuntimeException( |
| pDest, OUSTR("no exception has been thrown via invocation?!") ); |
| } |
| } |
| } |
| //______________________________________________________________________________ |
| void AdapterImpl::getValue( |
| const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * [], uno_Any ** ppException ) |
| { |
| uno_Any aInvokRet; |
| void * pInvokArgs[1]; |
| pInvokArgs[0] = |
| &((typelib_InterfaceMemberTypeDescription *)pMemberType)->pMemberName; |
| uno_Any aInvokExc; |
| uno_Any * pInvokExc = &aInvokExc; |
| |
| // getValue() |
| (*m_pReceiver->pDispatcher)( |
| m_pReceiver, m_pFactory->m_pGetValueTD, |
| &aInvokRet, pInvokArgs, &pInvokExc ); |
| |
| if (pInvokExc) // getValue() call exception |
| { |
| handleInvokExc( *ppException, pInvokExc ); |
| ::uno_any_destruct( pInvokExc, 0 ); // cleanup |
| } |
| else // invocation call succeeded |
| { |
| if (coerce_construct( |
| pReturn, |
| ((typelib_InterfaceAttributeTypeDescription *) |
| pMemberType)->pAttributeTypeRef, |
| &aInvokRet, *ppException )) |
| { |
| *ppException = 0; // no exceptions be thrown |
| } |
| ::uno_any_destruct( &aInvokRet, 0 ); |
| } |
| } |
| //______________________________________________________________________________ |
| void AdapterImpl::setValue( |
| const typelib_TypeDescription * pMemberType, |
| void *, void * pArgs[], uno_Any ** ppException ) |
| { |
| uno_Any aInvokVal; |
| ::uno_type_any_construct( |
| &aInvokVal, pArgs[0], |
| ((typelib_InterfaceAttributeTypeDescription *) |
| pMemberType)->pAttributeTypeRef, 0 ); |
| |
| void * pInvokArgs[2]; |
| pInvokArgs[0] = |
| &((typelib_InterfaceMemberTypeDescription *)pMemberType)->pMemberName; |
| pInvokArgs[1] = &aInvokVal; |
| uno_Any aInvokExc; |
| uno_Any * pInvokExc = &aInvokExc; |
| |
| // setValue() |
| (*m_pReceiver->pDispatcher)( |
| m_pReceiver, m_pFactory->m_pSetValueTD, 0, pInvokArgs, &pInvokExc ); |
| |
| if (pInvokExc) // setValue() call exception |
| { |
| handleInvokExc( *ppException, pInvokExc ); |
| ::uno_any_destruct( pInvokExc, 0 ); // cleanup |
| } |
| else // invocation call succeeded |
| { |
| *ppException = 0; // no exceptions be thrown |
| } |
| |
| ::uno_any_destruct( &aInvokVal, 0 ); // cleanup |
| } |
| //______________________________________________________________________________ |
| void AdapterImpl::invoke( |
| const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * pArgs[], uno_Any ** ppException ) |
| { |
| sal_Int32 nParams = |
| ((typelib_InterfaceMethodTypeDescription *)pMemberType)->nParams; |
| typelib_MethodParameter * pFormalParams = |
| ((typelib_InterfaceMethodTypeDescription *)pMemberType)->pParams; |
| |
| // in params |
| uno_Sequence * pInParamsSeq = 0; |
| ::uno_sequence_construct( |
| &pInParamsSeq, m_pFactory->m_pAnySeqTD, 0, nParams, 0 ); |
| uno_Any * pInAnys = (uno_Any *)pInParamsSeq->elements; |
| sal_Int32 nOutParams = 0; |
| sal_Int32 nPos; |
| for ( nPos = nParams; nPos--; ) |
| { |
| typelib_MethodParameter const & rParam = pFormalParams[nPos]; |
| if (rParam.bIn) // is in/inout param |
| { |
| ::uno_type_any_assign( |
| &pInAnys[nPos], pArgs[nPos], rParam.pTypeRef, 0, 0 ); |
| } |
| // else: pure out is empty any |
| |
| if (rParam.bOut) |
| ++nOutParams; |
| } |
| |
| // out params, out indices |
| uno_Sequence * pOutIndices; |
| uno_Sequence * pOutParams; |
| // return value |
| uno_Any aInvokRet; |
| // perform call |
| void * pInvokArgs[4]; |
| pInvokArgs[0] = |
| &((typelib_InterfaceMemberTypeDescription *)pMemberType)->pMemberName; |
| pInvokArgs[1] = &pInParamsSeq; |
| pInvokArgs[2] = &pOutIndices; |
| pInvokArgs[3] = &pOutParams; |
| uno_Any aInvokExc; |
| uno_Any * pInvokExc = &aInvokExc; |
| |
| // invoke() call |
| (*m_pReceiver->pDispatcher)( |
| m_pReceiver, m_pFactory->m_pInvokMethodTD, |
| &aInvokRet, pInvokArgs, &pInvokExc ); |
| |
| if (pInvokExc) |
| { |
| handleInvokExc( *ppException, pInvokExc ); |
| ::uno_any_destruct( pInvokExc, 0 ); // cleanup |
| } |
| else // no invocation exception |
| { |
| // write changed out params |
| OSL_ENSURE( |
| pOutParams->nElements == nOutParams && |
| pOutIndices->nElements == nOutParams, |
| "### out params lens differ!" ); |
| if (pOutParams->nElements == nOutParams && |
| pOutIndices->nElements == nOutParams) |
| { |
| sal_Int16 * pIndices = (sal_Int16 *)pOutIndices->elements; |
| uno_Any * pOut = (uno_Any *)pOutParams->elements; |
| for ( nPos = 0; nPos < nOutParams; ++nPos ) |
| { |
| sal_Int32 nIndex = pIndices[nPos]; |
| OSL_ENSURE( nIndex < nParams, "### illegal index!" ); |
| typelib_MethodParameter const & rParam = pFormalParams[nIndex]; |
| bool succ; |
| if (rParam.bIn) // is in/inout param |
| { |
| succ = coerce_assign( |
| pArgs[nIndex], rParam.pTypeRef, &pOut[nPos], |
| *ppException ); |
| } |
| else // pure out |
| { |
| succ = coerce_construct( |
| pArgs[nIndex], rParam.pTypeRef, &pOut[nPos], |
| *ppException ); |
| } |
| if (! succ) // cleanup of out params |
| { |
| for ( sal_Int32 n = 0; n <= nPos; ++n ) |
| { |
| sal_Int32 nIndex2 = pIndices[n]; |
| OSL_ENSURE( nIndex2 < nParams, "### illegal index!" ); |
| typelib_MethodParameter const & rParam2 = |
| pFormalParams[nIndex2]; |
| if (! rParam2.bIn) // is pure out param |
| { |
| ::uno_type_destructData( |
| pArgs[nIndex2], rParam2.pTypeRef, 0 ); |
| } |
| } |
| } |
| } |
| if (nPos == pOutIndices->nElements) |
| { |
| // out param copy ok; write return value |
| if (coerce_construct( |
| pReturn, |
| ((typelib_InterfaceMethodTypeDescription *) |
| pMemberType)->pReturnTypeRef, |
| &aInvokRet, *ppException )) |
| { |
| *ppException = 0; // no exception |
| } |
| } |
| } |
| else |
| { |
| // set runtime exception |
| constructRuntimeException( |
| *ppException, |
| OUSTR("out params lengths differ after invocation call!") ); |
| } |
| // cleanup invok out params |
| ::uno_destructData( &pOutIndices, m_pFactory->m_pShortSeqTD, 0 ); |
| ::uno_destructData( &pOutParams, m_pFactory->m_pAnySeqTD, 0 ); |
| // cleanup invok return value |
| ::uno_any_destruct( &aInvokRet, 0 ); |
| } |
| // cleanup constructed in params |
| ::uno_destructData( &pInParamsSeq, m_pFactory->m_pAnySeqTD, 0 ); |
| } |
| |
| extern "C" |
| { |
| //______________________________________________________________________________ |
| static void SAL_CALL adapter_acquire( uno_Interface * pUnoI ) |
| { |
| static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->acquire(); |
| } |
| //______________________________________________________________________________ |
| static void SAL_CALL adapter_release( uno_Interface * pUnoI ) |
| { |
| static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->release(); |
| } |
| //______________________________________________________________________________ |
| static void SAL_CALL adapter_dispatch( |
| uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType, |
| void * pReturn, void * pArgs[], uno_Any ** ppException ) |
| { |
| // query to emulated interface |
| switch (((typelib_InterfaceMemberTypeDescription *)pMemberType)->nPosition) |
| { |
| case 0: // queryInterface() |
| { |
| AdapterImpl * that = |
| static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter; |
| *ppException = 0; // no exc |
| typelib_TypeDescriptionReference * pDemanded = |
| *(typelib_TypeDescriptionReference **)pArgs[0]; |
| // pInterfaces[0] is XInterface |
| for ( sal_Int32 nPos = 0; nPos < that->m_nInterfaces; ++nPos ) |
| { |
| typelib_InterfaceTypeDescription * pTD = |
| that->m_pInterfaces[nPos].m_pTypeDescr; |
| while (pTD) |
| { |
| if (type_equals( |
| ((typelib_TypeDescription *)pTD)->pWeakRef, pDemanded )) |
| { |
| uno_Interface * pUnoI2 = &that->m_pInterfaces[nPos]; |
| ::uno_any_construct( |
| (uno_Any *)pReturn, &pUnoI2, |
| (typelib_TypeDescription *)pTD, 0 ); |
| return; |
| } |
| pTD = pTD->pBaseTypeDescription; |
| } |
| } |
| ::uno_any_construct( (uno_Any *)pReturn, 0, 0, 0 ); // clear() |
| break; |
| } |
| case 1: // acquire() |
| *ppException = 0; // no exc |
| adapter_acquire( pUnoI ); |
| break; |
| case 2: // release() |
| *ppException = 0; // no exc |
| adapter_release( pUnoI ); |
| break; |
| |
| default: |
| { |
| AdapterImpl * that = |
| static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter; |
| if (pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD) |
| { |
| that->invoke( pMemberType, pReturn, pArgs, ppException ); |
| } |
| else // attribute |
| { |
| if (pReturn) |
| that->getValue( pMemberType, pReturn, pArgs, ppException ); |
| else |
| that->setValue( pMemberType, pReturn, pArgs, ppException ); |
| } |
| } |
| } |
| } |
| } |
| //______________________________________________________________________________ |
| AdapterImpl::AdapterImpl( |
| void * key, Reference< script::XInvocation > const & xReceiver, |
| const Sequence< Type > & rTypes, |
| FactoryImpl * pFactory ) |
| SAL_THROW( (RuntimeException) ) |
| : m_nRef( 1 ), |
| m_pFactory( pFactory ), |
| m_key( key ) |
| { |
| // init adapters |
| m_nInterfaces = rTypes.getLength(); |
| m_pInterfaces = new InterfaceAdapterImpl[ rTypes.getLength() ]; |
| const Type * pTypes = rTypes.getConstArray(); |
| for ( sal_Int32 nPos = rTypes.getLength(); nPos--; ) |
| { |
| InterfaceAdapterImpl * pInterface = &m_pInterfaces[nPos]; |
| pInterface->acquire = adapter_acquire; |
| pInterface->release = adapter_release; |
| pInterface->pDispatcher = adapter_dispatch; |
| pInterface->m_pAdapter = this; |
| pInterface->m_pTypeDescr = 0; |
| pTypes[nPos].getDescription( |
| (typelib_TypeDescription **)&pInterface->m_pTypeDescr ); |
| OSL_ASSERT( pInterface->m_pTypeDescr ); |
| if (! pInterface->m_pTypeDescr) |
| { |
| for ( sal_Int32 n = 0; n < nPos; ++n ) |
| { |
| ::typelib_typedescription_release( |
| (typelib_TypeDescription *) |
| m_pInterfaces[ n ].m_pTypeDescr ); |
| } |
| delete [] m_pInterfaces; |
| throw RuntimeException( |
| OUSTR("cannot retrieve all interface type infos!"), |
| Reference< XInterface >() ); |
| } |
| } |
| |
| // map receiver |
| m_pReceiver = (uno_Interface *)m_pFactory->m_aCpp2Uno.mapInterface( |
| xReceiver.get(), ::getCppuType( &xReceiver ) ); |
| OSL_ASSERT( 0 != m_pReceiver ); |
| if (! m_pReceiver) |
| { |
| throw RuntimeException( |
| OUSTR("cannot map receiver!"), Reference< XInterface >() ); |
| } |
| |
| m_pFactory->acquire(); |
| } |
| |
| //______________________________________________________________________________ |
| FactoryImpl::FactoryImpl( Reference< XComponentContext > const & xContext ) |
| SAL_THROW( (RuntimeException) ) |
| : m_pInvokMethodTD( 0 ), |
| m_pSetValueTD( 0 ), |
| m_pGetValueTD( 0 ), |
| m_pAnySeqTD( 0 ), |
| m_pShortSeqTD( 0 ), |
| m_pConvertToTD( 0 ) |
| { |
| // C++/UNO bridge |
| OUString aCppEnvTypeName = OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME); |
| OUString aUnoEnvTypeName = OUSTR(UNO_LB_UNO); |
| m_aUno2Cpp = Mapping( aUnoEnvTypeName, aCppEnvTypeName ); |
| m_aCpp2Uno = Mapping( aCppEnvTypeName, aUnoEnvTypeName ); |
| OSL_ENSURE( |
| m_aUno2Cpp.is() && m_aCpp2Uno.is(), "### no uno / C++ mappings!" ); |
| |
| // type converter |
| Reference< script::XTypeConverter > xConverter( |
| xContext->getServiceManager()->createInstanceWithContext( |
| OUString( |
| RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.Converter") ), |
| xContext ), |
| UNO_QUERY_THROW ); |
| m_pConverter = (uno_Interface *)m_aCpp2Uno.mapInterface( |
| xConverter.get(), ::getCppuType( &xConverter ) ); |
| OSL_ASSERT( 0 != m_pConverter ); |
| |
| // some type info: |
| // sequence< any > |
| Type const & rAnySeqType = ::getCppuType( (const Sequence< Any > *)0 ); |
| rAnySeqType.getDescription( &m_pAnySeqTD ); |
| // sequence< short > |
| const Type & rShortSeqType = |
| ::getCppuType( (const Sequence< sal_Int16 > *)0 ); |
| rShortSeqType.getDescription( &m_pShortSeqTD ); |
| // script.XInvocation |
| typelib_TypeDescription * pTD = 0; |
| const Type & rInvType = ::getCppuType( |
| (const Reference< script::XInvocation > *)0 ); |
| TYPELIB_DANGER_GET( &pTD, rInvType.getTypeLibType() ); |
| typelib_InterfaceTypeDescription * pITD; |
| pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD); |
| if( ! pITD->aBase.bComplete ) |
| typelib_typedescription_complete( &pTD ); |
| ::typelib_typedescriptionreference_getDescription( |
| &m_pInvokMethodTD, pITD->ppMembers[ 1 ] ); // invoke() |
| ::typelib_typedescriptionreference_getDescription( |
| &m_pSetValueTD, pITD->ppMembers[ 2 ] ); // setValue() |
| ::typelib_typedescriptionreference_getDescription( |
| &m_pGetValueTD, pITD->ppMembers[ 3 ] ); // getValue() |
| // script.XTypeConverter |
| const Type & rTCType = |
| ::getCppuType( (const Reference< script::XTypeConverter > *)0 ); |
| TYPELIB_DANGER_GET( &pTD, rTCType.getTypeLibType() ); |
| pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD); |
| ::typelib_typedescriptionreference_getDescription( |
| &m_pConvertToTD, pITD->ppMembers[ 0 ] ); // convertTo() |
| TYPELIB_DANGER_RELEASE( pTD ); |
| |
| if (!m_pInvokMethodTD || !m_pSetValueTD || !m_pGetValueTD || |
| !m_pConvertToTD || |
| !m_pAnySeqTD || !m_pShortSeqTD) |
| { |
| throw RuntimeException( |
| OUSTR("missing type descriptions!"), Reference< XInterface >() ); |
| } |
| |
| g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt ); |
| } |
| //______________________________________________________________________________ |
| FactoryImpl::~FactoryImpl() SAL_THROW( () ) |
| { |
| ::typelib_typedescription_release( m_pInvokMethodTD ); |
| ::typelib_typedescription_release( m_pSetValueTD ); |
| ::typelib_typedescription_release( m_pGetValueTD ); |
| ::typelib_typedescription_release( m_pAnySeqTD ); |
| ::typelib_typedescription_release( m_pShortSeqTD ); |
| ::typelib_typedescription_release( m_pConvertToTD ); |
| |
| (*m_pConverter->release)( m_pConverter ); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| OSL_ENSURE( m_receiver2adapters.empty(), "### still adapters out there!?" ); |
| #endif |
| g_moduleCount.modCnt.release( &g_moduleCount.modCnt ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| static inline AdapterImpl * lookup_adapter( |
| t_ptr_set ** pp_adapter_set, |
| t_ptr_map & map, void * key, Sequence< Type > const & rTypes ) |
| SAL_THROW( () ) |
| { |
| t_ptr_set & adapters_set = map[ key ]; |
| *pp_adapter_set = &adapters_set; |
| if (adapters_set.empty()) |
| return 0; // shortcut |
| // find matching adapter |
| Type const * pTypes = rTypes.getConstArray(); |
| sal_Int32 nTypes = rTypes.getLength(); |
| t_ptr_set::const_iterator iPos( adapters_set.begin() ); |
| t_ptr_set::const_iterator const iEnd( adapters_set.end() ); |
| while (iEnd != iPos) |
| { |
| AdapterImpl * that = reinterpret_cast< AdapterImpl * >( *iPos ); |
| // iterate thru all types if that is a matching adapter |
| sal_Int32 nPosTypes; |
| for ( nPosTypes = nTypes; nPosTypes--; ) |
| { |
| Type const & rType = pTypes[ nPosTypes ]; |
| // find in adapter's type list |
| sal_Int32 nPos; |
| for ( nPos = that->m_nInterfaces; nPos--; ) |
| { |
| if (::typelib_typedescriptionreference_isAssignableFrom( |
| rType.getTypeLibType(), |
| ((typelib_TypeDescription *)that-> |
| m_pInterfaces[ nPos ].m_pTypeDescr)->pWeakRef )) |
| { |
| // found |
| break; |
| } |
| } |
| if (nPos < 0) // type not found => next adapter |
| break; |
| } |
| if (nPosTypes < 0) // all types found |
| return that; |
| ++iPos; |
| } |
| return 0; |
| } |
| |
| // XInvocationAdapterFactory2 impl |
| //______________________________________________________________________________ |
| Reference< XInterface > FactoryImpl::createAdapter( |
| const Reference< script::XInvocation > & xReceiver, |
| const Sequence< Type > & rTypes ) |
| throw (RuntimeException) |
| { |
| Reference< XInterface > xRet; |
| if (xReceiver.is() && rTypes.getLength()) |
| { |
| t_ptr_set * adapter_set; |
| AdapterImpl * that; |
| Reference< XInterface > xKey( xReceiver, UNO_QUERY ); |
| { |
| ClearableMutexGuard guard( m_mutex ); |
| that = lookup_adapter( |
| &adapter_set, m_receiver2adapters, xKey.get(), rTypes ); |
| if (0 == that) // no entry |
| { |
| guard.clear(); |
| // create adapter; already acquired: m_nRef == 1 |
| AdapterImpl * pNew = |
| new AdapterImpl( xKey.get(), xReceiver, rTypes, this ); |
| // lookup again |
| ClearableMutexGuard guard2( m_mutex ); |
| that = lookup_adapter( |
| &adapter_set, m_receiver2adapters, xKey.get(), rTypes ); |
| if (0 == that) // again no entry |
| { |
| pair< t_ptr_set::iterator, bool > insertion( |
| adapter_set->insert( pNew ) ); |
| OSL_ASSERT( insertion.second ); |
| that = pNew; |
| } |
| else |
| { |
| that->acquire(); |
| guard2.clear(); |
| delete pNew; // has never been inserted |
| } |
| } |
| else // found adapter |
| { |
| that->acquire(); |
| } |
| } |
| // map one interface to C++ |
| uno_Interface * pUnoI = &that->m_pInterfaces[ 0 ]; |
| m_aUno2Cpp.mapInterface( |
| (void **)&xRet, pUnoI, ::getCppuType( &xRet ) ); |
| that->release(); |
| OSL_ASSERT( xRet.is() ); |
| if (! xRet.is()) |
| { |
| throw RuntimeException( |
| OUSTR("mapping UNO to C++ failed!"), |
| Reference< XInterface >() ); |
| } |
| } |
| return xRet; |
| } |
| // XInvocationAdapterFactory impl |
| //______________________________________________________________________________ |
| Reference< XInterface > FactoryImpl::createAdapter( |
| const Reference< script::XInvocation > & xReceiver, const Type & rType ) |
| throw (RuntimeException) |
| { |
| return createAdapter( xReceiver, Sequence< Type >( &rType, 1 ) ); |
| } |
| |
| // XServiceInfo |
| //______________________________________________________________________________ |
| OUString FactoryImpl::getImplementationName() |
| throw (RuntimeException) |
| { |
| return invadp_getImplementationName(); |
| } |
| //______________________________________________________________________________ |
| sal_Bool FactoryImpl::supportsService( const OUString & rServiceName ) |
| throw (RuntimeException) |
| { |
| const Sequence< OUString > & rSNL = getSupportedServiceNames(); |
| const OUString * pArray = rSNL.getConstArray(); |
| for ( sal_Int32 nPos = rSNL.getLength(); nPos--; ) |
| { |
| if (pArray[nPos].equals( rServiceName )) |
| return sal_True; |
| } |
| return sal_False; |
| } |
| //______________________________________________________________________________ |
| Sequence< OUString > FactoryImpl::getSupportedServiceNames() |
| throw (RuntimeException) |
| { |
| return invadp_getSupportedServiceNames(); |
| } |
| |
| //============================================================================== |
| static Reference< XInterface > SAL_CALL FactoryImpl_create( |
| const Reference< XComponentContext > & xContext ) |
| throw (Exception) |
| { |
| Reference< XInterface > rRet; |
| { |
| MutexGuard guard( Mutex::getGlobalMutex() ); |
| static WeakReference < XInterface > rwInstance; |
| rRet = rwInstance; |
| |
| if( ! rRet.is() ) |
| { |
| rRet = (::cppu::OWeakObject *)new FactoryImpl( xContext ); |
| rwInstance = rRet; |
| } |
| } |
| return rRet; |
| } |
| |
| } |
| |
| |
| //############################################################################## |
| //############################################################################## |
| //############################################################################## |
| |
| static struct ::cppu::ImplementationEntry g_entries[] = |
| { |
| { |
| ::stoc_invadp::FactoryImpl_create, |
| ::stoc_invadp::invadp_getImplementationName, |
| ::stoc_invadp::invadp_getSupportedServiceNames, |
| ::cppu::createSingleComponentFactory, |
| &::stoc_invadp::g_moduleCount.modCnt , 0 |
| }, |
| { 0, 0, 0, 0, 0, 0 } |
| }; |
| |
| extern "C" |
| { |
| sal_Bool SAL_CALL component_canUnload( |
| TimeValue *pTime ) |
| { |
| return ::stoc_invadp::g_moduleCount.canUnload( |
| &::stoc_invadp::g_moduleCount, pTime ); |
| } |
| |
| //============================================================================== |
| void SAL_CALL component_getImplementationEnvironment( |
| const sal_Char ** ppEnvTypeName, uno_Environment ** ) |
| { |
| *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; |
| } |
| |
| //============================================================================== |
| void * SAL_CALL component_getFactory( |
| const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) |
| { |
| return ::cppu::component_getFactoryHelper( |
| pImplName, pServiceManager, pRegistryKey , g_entries ); |
| } |
| } |