From 0c7f0636d433bed508332a537550505ced3cb7a4 Mon Sep 17 00:00:00 2001 From: Kurt Zenker Date: Wed, 9 May 2007 12:31:37 +0000 Subject: INTEGRATION: CWS bunoexttm (1.1.2); FILE ADDED 2006/12/19 12:05:23 kr 1.1.2.1: added: moved cli_uno bridge from bridges to here --- cli_ure/source/uno_bridge/cli_proxy.cxx | 1185 +++++++++++++++++++++++++++++++ 1 file changed, 1185 insertions(+) create mode 100644 cli_ure/source/uno_bridge/cli_proxy.cxx (limited to 'cli_ure/source/uno_bridge/cli_proxy.cxx') diff --git a/cli_ure/source/uno_bridge/cli_proxy.cxx b/cli_ure/source/uno_bridge/cli_proxy.cxx new file mode 100644 index 000000000000..f16a0e69e21e --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.cxx @@ -0,0 +1,1185 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: cli_proxy.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: kz $ $Date: 2007-05-09 13:31:37 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" +#include "typelib/typedescription.h" +#include "rtl/ustrbuf.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "osl/mutex.hxx" +#include "cli_proxy.h" +#include "cli_base.h" +#include "cli_bridge.h" + +namespace sr = System::Reflection; +namespace st = System::Text; +namespace sre = System::Reflection::Emit; +namespace sc = System::Collections; +namespace srrm = System::Runtime::Remoting::Messaging; +namespace srr = System::Runtime::Remoting; +namespace srrp = System::Runtime::Remoting::Proxies; +namespace sri = System::Runtime::InteropServices; +namespace sd = System::Diagnostics; +namespace css = com::sun::star; +namespace ucss = unoidl::com::sun::star; + +#using +#using + +using namespace cli_uno; +using namespace rtl; +extern "C" +{ +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); +//------------------------------------------------------------------------------ +void SAL_CALL cli_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args[], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C(); + + +} + +namespace cli_uno +{ + +UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI, + typelib_InterfaceTypeDescription* td): + + m_unoI(unoI), + m_typeDesc(td), + m_bridge(bridge) +{ + m_bridge->acquire(); + m_type = mapUnoType(reinterpret_cast(td)); + m_unoI->acquire(m_unoI); + typelib_typedescription_acquire(&m_typeDesc->aBase); + if ( ! m_typeDesc->aBase.bComplete) + { + typelib_TypeDescription* _pt = &m_typeDesc->aBase; + sal_Bool bComplete = ::typelib_typedescription_complete( & _pt); + if( ! bComplete) + { + OUStringBuffer buf( 128 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "cannot make type complete: ") ); + buf.append( *reinterpret_cast< OUString const * >( + & m_typeDesc->aBase.pTypeName)); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + } +} +UnoInterfaceInfo::~UnoInterfaceInfo() +{ + //accessing unmanaged objects is ok. + m_bridge->m_uno_env->revokeInterface( + m_bridge->m_uno_env, m_unoI ); + m_bridge->release(); + + m_unoI->release(m_unoI); + typelib_typedescription_release( + reinterpret_cast(m_typeDesc)); +} + +UnoInterfaceProxy::UnoInterfaceProxy( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const OUString& oid ) + :RealProxy(__typeof(MarshalByRefObject)), + m_bridge(bridge), + m_oid(mapUnoString(oid.pData)), + m_sTypeName(m_system_Object_String) +{ + m_bridge->acquire(); + // create the list that holds all UnoInterfaceInfos + m_listIfaces = new ArrayList(10); + m_numUnoIfaces = 0; + m_listAdditionalProxies = new ArrayList(); + m_nlistAdditionalProxies = 0; + //put the information of the first UNO interface into the arraylist +#if OSL_DEBUG_LEVEL >= 2 + _numInterfaces = 0; + _sInterfaces = NULL; +#endif + addUnoInterface(pUnoI, pTD); + +} + +UnoInterfaceProxy::~UnoInterfaceProxy() +{ +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Destroying proxy " + S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "), + m_oid)); + + sd::Trace::WriteLine( mapUnoString(_sInterfaces)); + rtl_uString_release(_sInterfaces); +#endif + //m_bridge is unmanaged, therefore we can access it in this finalizer + CliEnvHolder::g_cli_env->revokeInterface(m_oid); + m_bridge->release(); +} + + +System::Object* UnoInterfaceProxy::create( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const OUString& oid) +{ + UnoInterfaceProxy* proxyHandler= + new UnoInterfaceProxy(bridge, pUnoI, pTD, oid); + System::Object* proxy= proxyHandler->GetTransparentProxy(); + CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData)); + return proxy; +} + + +void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI, + typelib_InterfaceTypeDescription* pTd) +{ + sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator(); + System::Threading::Monitor::Enter(this); + try + { + while (enumInfos->MoveNext()) + { + UnoInterfaceInfo* info = static_cast( + enumInfos->Current); +#if OSL_DEBUG_LEVEL > 1 + System::Type * t1; + System::Type * t2; + t1 = mapUnoType( + reinterpret_cast(info->m_typeDesc) ); + t2 = mapUnoType( + reinterpret_cast(pTd) ); +#endif + if (typelib_typedescription_equals( + reinterpret_cast(info->m_typeDesc), + reinterpret_cast(pTd))) + { + return; + } + } + OUString oid(mapCliString(m_oid)); + (*m_bridge->m_uno_env->registerInterface)( + m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ), + oid.pData, pTd); + //This proxy does not contain the uno_Interface. Add it. + m_listIfaces->Add(new UnoInterfaceInfo(m_bridge, pUnoI, pTd)); + m_numUnoIfaces = m_listIfaces->Count; +#if OSL_DEBUG_LEVEL >= 2 + System::String * sInterfaceName = static_cast( + m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName; + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Creating proxy for uno object, " + S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName)); + // add to the string that contains all interface names + _numInterfaces ++; + OUStringBuffer buf(512); + buf.appendAscii("\t"); + buf.append( OUString::valueOf((sal_Int32)_numInterfaces)); + buf.appendAscii(". "); + buf.append(mapCliString(sInterfaceName)); + buf.appendAscii("\n"); + OUString _sNewInterface = buf.makeStringAndClear(); + rtl_uString * __pin * pp_sInterfaces = & _sInterfaces; + rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces, + _sNewInterface.pData); +#endif + } + __finally { + System::Threading::Monitor::Exit(this); + } +} + + +// IRemotingTypeInfo +bool UnoInterfaceProxy::CanCastTo(System::Type* fromType, + System::Object*) +{ + if (fromType == __typeof(System::Object)) // trivial case + return true; + + System::Threading::Monitor::Enter(this); + try + { + if (0 != findInfo( fromType )) // proxy supports demanded interface + return true; + + //query an uno interface for the required type + + // we use the first interface in the list (m_listIfaces) to make + // the queryInterface call + UnoInterfaceInfo* info = + static_cast(m_listIfaces->get_Item(0)); + css::uno::TypeDescription membertd( + reinterpret_cast( + info->m_typeDesc)->ppAllMembers[0]); + System::Object *args[] = new System::Object*[1]; + + args[0] = fromType; + __box uno::Any * pAny; + System::Object* pException = NULL; + + pAny= static_cast<__box uno::Any *>( + m_bridge->call_uno( + info->m_unoI, + membertd.get(), + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pReturnTypeRef, + 1, + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pParams, + args, NULL, &pException) ); + + // handle regular exception from target + OSL_ENSURE( + 0 == pException, + OUStringToOString( + mapCliString( pException->ToString()), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + if (pAny->Type != __typeof (void)) // has value? + { + if (0 != findInfo( fromType )) + { + // proxy now supports demanded interface + return true; + } + + // via aggregation: it is possible that queryInterface() returns + // and interface with a different oid. + // That way, this type is supported for the CLI + // interpreter (CanCastTo() returns true) + ::System::Object * obj = pAny->Value; + OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) ); + if (srr::RemotingServices::IsTransparentProxy( obj )) + { + UnoInterfaceProxy * proxy = + static_cast< UnoInterfaceProxy * >( + srr::RemotingServices::GetRealProxy( obj ) ); + OSL_ASSERT( 0 != proxy->findInfo( fromType ) ); + m_listAdditionalProxies->Add( proxy ); + m_nlistAdditionalProxies = m_listAdditionalProxies->Count; + OSL_ASSERT( 0 != findInfo( fromType ) ); + return true; + } + } + } + catch (BridgeRuntimeError& e) + { + (void) e; // avoid warning + OSL_ENSURE( + 0, OUStringToOString( + e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (System::Exception* e) + { + System::String* msg= new System::String( + S"An unexpected CLI exception occurred in " + S"UnoInterfaceProxy::CanCastTo(). Original" + S"message: \n"); + msg= System::String::Concat(msg, e->get_Message()); + OSL_ENSURE( + 0, OUStringToOString( + mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (...) + { + OSL_ENSURE( + 0, "An unexpected native C++ exception occurred in " + "UnoInterfaceProxy::CanCastTo()" ); + } + __finally + { + System::Threading::Monitor::Exit(this); + } + return false; +} + +srrm::IMessage* UnoInterfaceProxy::invokeObject( + sc::IDictionary* props, + srrm::LogicalCallContext* context, + srrm::IMethodCallMessage* mcm) +{ + System::Object* retMethod = 0; + System::String* sMethod = static_cast + (props->get_Item(m_methodNameString)); + System::Object* args[] = static_cast( + props->get_Item(m_ArgsString)); + if (m_Equals_String->Equals(sMethod)) + { + // Object.Equals + OSL_ASSERT(args->get_Length() == 1); + srrp::RealProxy* rProxy = srr::RemotingServices::GetRealProxy(args[0]); + bool bDone = false; + if (rProxy) + { + UnoInterfaceProxy* unoProxy = + dynamic_cast(rProxy); + if (unoProxy) + { + bool b = m_oid->Equals(unoProxy->getOid()); + retMethod = __box(b); + bDone = true; + } + } + if (bDone == false) + { + //no proxy or not our proxy, therefore Equals must be false + retMethod = __box(false); + } + } + else if (m_GetHashCode_String->Equals(sMethod)) + { + // Object.GetHashCode + int nHash = m_oid->GetHashCode(); + retMethod = __box(nHash); + } + else if (m_GetType_String->Equals(sMethod)) + { + // Object.GetType + retMethod = __typeof(System::Object); + } + else if (m_ToString_String->Equals(sMethod)) + { + // Object.ToString + st::StringBuilder* sb = new st::StringBuilder(256); +// sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}" +// S". OID: {1}", m_type->ToString(), m_oid); + sb->AppendFormat(S"Uno object proxy. OID: {0}", m_oid); + retMethod = sb->ToString(); + } + else + { + //Either Object has new functions or a protected method was called + //which should not be possible + OSL_ASSERT(0); + } + srrm::IMessage* retVal= new srrm::ReturnMessage( + retMethod, new System::Object*[0], 0, context, mcm); + return retVal; +} + +UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type ) +{ + for (int i = 0; i < m_numUnoIfaces; i++) + { + UnoInterfaceInfo* tmpInfo = static_cast( + m_listIfaces->get_Item(i)); + if (type->IsAssignableFrom(tmpInfo->m_type)) + return tmpInfo; + } + for ( int i = 0; i < m_nlistAdditionalProxies; ++i ) + { + UnoInterfaceProxy * proxy = + static_cast< UnoInterfaceProxy * >( + m_listAdditionalProxies->get_Item( i ) ); + UnoInterfaceInfo * info = proxy->findInfo( type ); + if (0 != info) + return info; + } + return 0; +} + +srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg) +{ + try + { + sc::IDictionary* props= callmsg->Properties; + srrm::LogicalCallContext* context= + static_cast( + props->get_Item(m_CallContextString)); + srrm::IMethodCallMessage* mcm= + static_cast(callmsg); + + //Find out which UNO interface is being called + System::String* sTypeName = static_cast( + props->get_Item(m_typeNameString)); + sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(',')); + + // Special Handling for System.Object methods + if(sTypeName->IndexOf(m_system_Object_String) != -1) + { + return invokeObject(props, context, mcm); + } + + System::Type* typeBeingCalled = loadCliType(sTypeName); + UnoInterfaceInfo* info = findInfo( typeBeingCalled ); + OSL_ASSERT( 0 != info ); + + // ToDo do without string conversion, a OUString is not needed here + // get the type description of the call + OUString usMethodName(mapCliString(static_cast( + props->get_Item(m_methodNameString)))); + typelib_TypeDescriptionReference ** ppAllMembers = + info->m_typeDesc->ppAllMembers; + sal_Int32 numberMembers = info->m_typeDesc->nAllMembers; + for ( sal_Int32 nPos = numberMembers; nPos--; ) + { + typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos]; + + // check usMethodName against fully qualified usTypeName + // of member_type; usTypeName is of the form + // "::" *(":@" "," ":" ) + OUString const & usTypeName = + OUString::unacquired( & member_type->pTypeName ); + +#if OSL_DEBUG_LEVEL >= 2 + System::String * pTypeName; + pTypeName = mapUnoString(usTypeName.pData); +#endif + sal_Int32 offset = usTypeName.indexOf( ':' ) + 2; + OSL_ASSERT( + offset >= 2 && offset < usTypeName.getLength() + && usTypeName[offset - 1] == ':' ); + sal_Int32 remainder = usTypeName.getLength() - offset; + + if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass) + { + if ((usMethodName.getLength() == remainder + || (usMethodName.getLength() < remainder + && usTypeName[offset + usMethodName.getLength()] == ':')) + && usTypeName.match(usMethodName, offset)) + { + TypeDescr member_td( member_type ); + typelib_InterfaceMethodTypeDescription * method_td = + (typelib_InterfaceMethodTypeDescription *) + member_td.get(); + + System::Object* args[] = static_cast( + props->get_Item(m_ArgsString)); + System::Type* argTypes[] = static_cast( + props->get_Item(m_methodSignatureString)); + System::Object* pExc = NULL; + System::Object * cli_ret = m_bridge->call_uno( + info->m_unoI, member_td.get(), + method_td->pReturnTypeRef, method_td->nParams, + method_td->pParams, args, argTypes, &pExc); + return constructReturnMessage(cli_ret, args, method_td, + callmsg, pExc); + break; + } + } + else + { + OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE == + member_type->eTypeClass ); + if (usMethodName.getLength() > 4 + && (usMethodName.getLength() - 4 == remainder + || (usMethodName.getLength() - 4 < remainder + && usTypeName[ + offset + (usMethodName.getLength() - 4)] == ':')) + && usMethodName[1] == 'e' && usMethodName[2] == 't' + && rtl_ustr_compare_WithLength( + usTypeName.getStr() + offset, + usMethodName.getLength() - 4, + usMethodName.getStr() + 4, + usMethodName.getLength() - 4) == 0) + { + if ('g' == usMethodName[0]) + { + TypeDescr member_td( member_type ); + typelib_InterfaceAttributeTypeDescription * attribute_td = + (typelib_InterfaceAttributeTypeDescription*) + member_td.get(); + + System::Object* pExc = NULL; + System::Object* cli_ret= m_bridge->call_uno( + info->m_unoI, member_td.get(), + attribute_td->pAttributeTypeRef, + 0, 0, + NULL, NULL, &pExc); + return constructReturnMessage(cli_ret, NULL, NULL, + callmsg, pExc); + } + else if ('s' == usMethodName[0]) + { + TypeDescr member_td( member_type ); + typelib_InterfaceAttributeTypeDescription * attribute_td = + (typelib_InterfaceAttributeTypeDescription *) + member_td.get(); + if (! attribute_td->bReadOnly) + { + typelib_MethodParameter param; + param.pTypeRef = attribute_td->pAttributeTypeRef; + param.bIn = sal_True; + param.bOut = sal_False; + + System::Object* args[] = + static_cast( + props->get_Item(m_ArgsString)); + System::Object* pExc = NULL; + m_bridge->call_uno( + info->m_unoI, member_td.get(), + ::getCppuVoidType().getTypeLibType(), + 1, ¶m, args, NULL, &pExc); + return constructReturnMessage(NULL, NULL, NULL, + callmsg, pExc); + } + else + { + return constructReturnMessage(NULL, NULL, NULL, + callmsg, NULL); + } + } + break; + } + } + } + // ToDo check if the message of the exception is not crippled + // the thing that should not be... no method info found! + OUStringBuffer buf( 64 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge]calling undeclared function on " + "interface ") ); + buf.append( *reinterpret_cast< OUString const * >( + & ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName)); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( usMethodName ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError & err) + { + srrm::IMethodCallMessage* mcm = + static_cast(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + mapUnoString(err.m_message.pData), NULL), mcm); + } + catch (System::Exception* e) + { + st::StringBuilder * sb = new st::StringBuilder(512); + sb->Append(new System::String( + S"An unexpected CLI exception occurred in " + S"UnoInterfaceProxy::Invoke. Original" + S"message: \n")); + sb->Append(e->get_Message()); + sb->Append((__wchar_t) '\n'); + sb->Append(e->get_StackTrace()); + srrm::IMethodCallMessage* mcm = + static_cast(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + sb->ToString(), NULL), mcm); + } + catch (...) + { + System::String* msg = new System::String( + S"An unexpected native C++ exception occurred in " + S"UnoInterfaceProxy::Invoke."); + srrm::IMethodCallMessage* mcm = + static_cast(callmsg); + return new srrm::ReturnMessage(new ucss::uno::RuntimeException( + msg, NULL), mcm); + } + return NULL; +} +/** If the argument args is NULL then this function is called for an attribute + method (either setXXX or getXXX). + For attributes the argument mtd is also NULL. +*/ +srrm::IMessage* UnoInterfaceProxy::constructReturnMessage( + System::Object* cliReturn, + System::Object* args[], + typelib_InterfaceMethodTypeDescription* mtd, + srrm::IMessage* msg, System::Object* exc) +{ + srrm::IMessage * retVal= NULL; + srrm::IMethodCallMessage* mcm = static_cast(msg); + if (exc) + { + retVal = new srrm::ReturnMessage( + dynamic_cast(exc), mcm); + } + else + { + sc::IDictionary* props= msg->get_Properties(); + srrm::LogicalCallContext* context= + static_cast( + props->get_Item(m_CallContextString)); + if (args != NULL) + { + // Method + //build the array of out parameters, allocate max length + System::Object* arOut[]= new System::Object*[mtd->nParams]; + int nOut = 0; + for (int i= 0; i < mtd->nParams; i++) + { + if (mtd->pParams[i].bOut) + { + arOut[i]= args[i]; + nOut++; + } + } + retVal= new srrm::ReturnMessage(cliReturn, arOut, nOut, + context, mcm); + } + else + { + // Attribute (getXXX) + retVal= new srrm::ReturnMessage(cliReturn, NULL, 0, + context, mcm); + } + } + return retVal; +} + +//################################################################################ +CliProxy::CliProxy(Bridge const* bridge, System::Object* cliI, + typelib_TypeDescription const* td, + const rtl::OUString& usOid): + m_ref(1), + m_bridge(bridge), + m_cliI(cliI), + m_unoType(const_cast(td)), + m_usOid(usOid), + m_oid(mapUnoString(usOid.pData)), + m_nInheritedInterfaces(0) +{ + m_bridge->acquire(); + uno_Interface::acquire = cli_proxy_acquire; + uno_Interface::release = cli_proxy_release; + uno_Interface::pDispatcher = cli_proxy_dispatch; + + m_unoType.makeComplete(); + m_type= mapUnoType(m_unoType.get()); + + makeMethodInfos(); +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: Creating proxy for cli object, " + S"id:\n\t{0}\n\t{1}"), m_oid, m_type)); +#endif + +} + +void CliProxy::makeMethodInfos() +{ +#if OSL_DEBUG_LEVEL >= 2 + System::Object* cliI; + System::Type* type; + cliI = m_cliI; + type = m_type; +#endif + + if (m_type->get_IsInterface() == false) + return; + sr::MethodInfo* arThisMethods[] = m_type->GetMethods(); + //get the inherited interfaces + System::Type* arInheritedIfaces[] = m_type->GetInterfaces(); + m_nInheritedInterfaces = arInheritedIfaces->get_Length(); + //array containing the number of methods for the interface and its + //inherited interfaces + m_arInterfaceMethodCount = new int __gc [m_nInheritedInterfaces + 1]; + //determine the number of all interface methods, including the inherited + //interfaces + int numMethods = arThisMethods->get_Length(); + for (int i= 0; i < m_nInheritedInterfaces; i++) + { + numMethods += arInheritedIfaces[i]->GetMethods()->get_Length(); + } + //array containing MethodInfos of the cli object + m_arMethodInfos = new sr::MethodInfo*[numMethods]; + //array containing MethodInfos of the interface + m_arInterfaceMethodInfos = new sr::MethodInfo*[numMethods]; + //array containing the mapping of Uno interface pos to pos in + //m_arMethodInfos + m_arUnoPosToCliPos = new System::Int32[numMethods]; + // initialize with -1 + for (int i = 0; i < numMethods; i++) + m_arUnoPosToCliPos[i] = -1; + +#if OSL_DEBUG_LEVEL >= 2 + sr::MethodInfo* arMethodInfosDbg[]; + sr::MethodInfo* arInterfaceMethodInfosDbg[]; + System::Int32 arInterfaceMethodCountDbg[]; + arMethodInfosDbg = m_arMethodInfos; + arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; + arInterfaceMethodCountDbg = m_arInterfaceMethodCount; +#endif + + + //fill m_arMethodInfos with the mappings + // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according + // to documentation + // but it is Type*[] instead. Bug in the framework? + System::Type* objType = m_cliI->GetType(); + try + { + int index = 0; + // now get the methods from the inherited interface + //arInheritedIfaces[0] is the direct base interface + //arInheritedIfaces[n] is the furthest inherited interface + //Start with the base interface + int nArLength = arInheritedIfaces->get_Length(); + for (;nArLength > 0; nArLength--) + { + sr::InterfaceMapping mapInherited = objType->GetInterfaceMap( + arInheritedIfaces[nArLength - 1]); + int numMethods = mapInherited.TargetMethods->get_Length(); + m_arInterfaceMethodCount[nArLength - 1] = numMethods; + for (int i = 0; i < numMethods; i++, index++) + { + m_arMethodInfos[index] = __try_cast( + mapInherited.TargetMethods[i]); + + m_arInterfaceMethodInfos[index] = __try_cast( + mapInherited.InterfaceMethods[i]); + } + } + //At last come the methods of the furthest derived interface + sr::InterfaceMapping map = objType->GetInterfaceMap(m_type); + nArLength = map.TargetMethods->get_Length(); + m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength; + for (int i = 0; i < nArLength; i++,index++) + { + m_arMethodInfos[index]= __try_cast( + map.TargetMethods[i]); + m_arInterfaceMethodInfos[index]= __try_cast( + map.InterfaceMethods[i]); + } + } + catch (System::InvalidCastException* ) + { + OUStringBuffer buf( 128 ); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge] preparing proxy for " + "cli interface: ") ); + buf.append(mapCliString(m_type->ToString() )); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" \nfailed!")); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } +} + +sr::MethodInfo* CliProxy::getMethodInfo(int nUnoFunctionPos, + const rtl::OUString& usMethodName, MethodKind methodKind) +{ + sr::MethodInfo* ret = NULL; +#if OSL_DEBUG_LEVEL >= 2 + System::String* sMethodNameDbg; + sr::MethodInfo* arMethodInfosDbg[]; + sr::MethodInfo* arInterfaceMethodInfosDbg[]; + System::Int32 arInterfaceMethodCountDbg[]; + System::Int32 arUnoPosToCliPosDbg[]; + sMethodNameDbg = mapUnoString(usMethodName.pData); + arMethodInfosDbg = m_arMethodInfos; + arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; + arInterfaceMethodCountDbg = m_arInterfaceMethodCount; + arUnoPosToCliPosDbg = m_arUnoPosToCliPos; +#endif + //deduct 3 for XInterface methods + nUnoFunctionPos -= 3; + System::Threading::Monitor::Enter(m_arUnoPosToCliPos); + try + { + int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos]; + if (cliPos != -1) + return m_arMethodInfos[cliPos]; + + //create the method function name + System::String* sMethodName = mapUnoString(usMethodName.pData); + switch (methodKind) + { + case MK_METHOD: + break; + case MK_SET: + sMethodName = System::String::Concat( + const_cast(Constants::sAttributeSet), + sMethodName); + break; + case MK_GET: + sMethodName = System::String::Concat( + const_cast(Constants::sAttributeGet), + sMethodName); + break; + default: + OSL_ASSERT(0); + } + //Find the cli interface method that corresponds to the Uno method +// System::String* sMethodName= mapUnoString(usMethodName.pData); + int indexCliMethod = -1; + //If the cli interfaces and their methods are in the same order + //as they were declared (inheritance chain and within the interface) + //then nUnoFunctionPos should lead to the correct method. However, + //the documentation does not say that this ordering is given. + if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name)) + indexCliMethod = nUnoFunctionPos; + else + { + int cMethods = m_arInterfaceMethodInfos->get_Length(); + for (int i = 0; i < cMethods; i++) + { + System::String* cliMethod = m_arInterfaceMethodInfos[i]->Name; + if (cliMethod->Equals(sMethodName)) + { + indexCliMethod = i; + break; + } + } + } + if (indexCliMethod == -1) + { + OUStringBuffer buf(256); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[cli_uno bridge] CliProxy::getMethodInfo():" + "cli object does not implement interface method: ")); + buf.append(usMethodName); + throw BridgeRuntimeError(buf.makeStringAndClear()); + return 0; + } + m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod; + ret = m_arMethodInfos[indexCliMethod]; + } + __finally + { + System::Threading::Monitor::Exit(m_arUnoPosToCliPos); + } + + return ret; +} + +CliProxy::~CliProxy() +{ +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + new System::String( + S"cli uno bridge: Destroying proxy for cli object, " + S"id:\n\t{0}\n\t{1}\n"), + m_oid, m_type)); +#endif + CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get())); + m_bridge->release(); +} + +uno_Interface* CliProxy::create(Bridge const * bridge, + System::Object* cliI, + typelib_TypeDescription const* pTD, + const rtl::OUString& ousOid) +{ + uno_Interface* proxy= static_cast( + new CliProxy(bridge, cliI, pTD, ousOid)); + + //register proxy with target environment (uno) + (*bridge->m_uno_env->registerProxyInterface)( + bridge->m_uno_env, + reinterpret_cast(&proxy), + cli_proxy_free, + ousOid.pData, (typelib_InterfaceTypeDescription*) pTD); + //register original interface + CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData), + mapUnoType((pTD))); + + return proxy; +} + + + +void SAL_CALL CliProxy::uno_DispatchMethod( + struct _uno_Interface *, + const struct _typelib_TypeDescription *, + void *, + void **, + uno_Any ** ) +{ +} +inline void CliProxy::acquire() const +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + // rebirth of proxy zombie + void * that = const_cast< CliProxy * >( this ); + // register at uno env + (*m_bridge->m_uno_env->registerProxyInterface)( + m_bridge->m_uno_env, &that, + cli_proxy_free, m_usOid.pData, + (typelib_InterfaceTypeDescription *)m_unoType.get() ); +#if OSL_DEBUG_LEVEL >= 2 + OSL_ASSERT( this == (void const * const)that ); +#endif + } +} +//--------------------------------------------------------------------------- +inline void CliProxy::release() const +{ + if (0 == osl_decrementInterlockedCount( &m_ref )) + { + // revoke from uno env on last release, + // The proxy can be resurrected if acquire is called before the uno + // environment calls cli_proxy_free. cli_proxy_free will + //delete the proxy. The environment does not acquire a registered + //proxy. + (*m_bridge->m_uno_env->revokeInterface)( + m_bridge->m_uno_env, const_cast< CliProxy * >( this ) ); + } +} +} + + + + +extern "C" +void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy ) + SAL_THROW_EXTERN_C() +{ + cli_uno::CliProxy * cliProxy = reinterpret_cast< + cli_uno::CliProxy * >( proxy ); + + delete cliProxy; +} + +extern "C" +void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI ); + cliProxy->acquire(); +} +//----------------------------------------------------------------------------- +extern "C" +void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI ); + cliProxy->release(); +} + +//------------------------------------------------------------------------------ +extern "C" + +void SAL_CALL cli_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C() +{ + CliProxy * proxy = static_cast< CliProxy* >( pUnoI ); + try + { + Bridge const* bridge = proxy->m_bridge; + + switch (member_td->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + + sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) + member_td)->nPosition; + typelib_InterfaceTypeDescription * iface_td = + (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); + OSL_ENSURE( + member_pos < iface_td->nAllMembers, + "### member pos out of range!" ); + sal_Int32 function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; + OSL_ENSURE( + function_pos < iface_td->nMapFunctionIndexToMemberIndex, + "### illegal function index!" ); + + if (uno_ret) // is getter method + { + OUString const& usAttrName= *(rtl_uString**)& + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + sr::MethodInfo* info = proxy->getMethodInfo(function_pos, + usAttrName, CliProxy::MK_GET); + bridge->call_cli( + proxy->m_cliI, + info, + ((typelib_InterfaceAttributeTypeDescription *)member_td) + ->pAttributeTypeRef, + 0, 0, // no params + uno_ret, 0, uno_exc ); + } + else // is setter method + { + OUString const& usAttrName= *(rtl_uString**) & + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + sr::MethodInfo* info = proxy->getMethodInfo(function_pos + 1, + usAttrName, CliProxy::MK_SET); + typelib_MethodParameter param; + param.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)member_td) + ->pAttributeTypeRef; + param.bIn = sal_True; + param.bOut = sal_False; + + bridge->call_cli( + proxy->m_cliI, + // set follows get method + info, + 0 /* indicates void return */, ¶m, 1, + 0, uno_args, uno_exc ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) + member_td)->nPosition; + typelib_InterfaceTypeDescription * iface_td = + (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); + OSL_ENSURE( + member_pos < iface_td->nAllMembers, + "### member pos out of range!" ); + sal_Int32 function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; + OSL_ENSURE( + function_pos < iface_td->nMapFunctionIndexToMemberIndex, + "### illegal function index!" ); + + switch (function_pos) + { + case 0: // queryInterface() + { + TypeDescr demanded_td( + *reinterpret_cast( + uno_args[0])); + if (typelib_TypeClass_INTERFACE + != demanded_td.get()->eTypeClass) + { + throw BridgeRuntimeError( + OUSTR("queryInterface() call demands an INTERFACE type!")); + } + + uno_Interface * pInterface = 0; + (*bridge->m_uno_env->getRegisteredInterface)( + bridge->m_uno_env, + (void **)&pInterface, proxy->m_usOid.pData, + (typelib_InterfaceTypeDescription *)demanded_td.get() ); + + if (0 == pInterface) + { + System::Type* mgdDemandedType = + mapUnoType(demanded_td.get()); + if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI )) + { +#if OSL_DEBUG_LEVEL > 0 + OUString usOid( + mapCliString( + CliEnvHolder::g_cli_env->getObjectIdentifier( + proxy->m_cliI ))); + OSL_ENSURE(usOid.equals( proxy->m_usOid ), + "### different oids!"); +#endif + uno_Interface* pUnoI = bridge->map_cli2uno( + proxy->m_cliI, demanded_td.get() ); + uno_any_construct( + (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 ); + (*pUnoI->release)( pUnoI ); + } + else // object does not support demanded interface + { + uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 ); + } + // no excetpion occured + *uno_exc = 0; + } + else + { + uno_any_construct( + reinterpret_cast< uno_Any * >( uno_ret ), + &pInterface, demanded_td.get(), 0 ); + (*pInterface->release)( pInterface ); + *uno_exc = 0; + } + break; + } + case 1: // acquire this proxy + cli_proxy_acquire(proxy); + *uno_exc = 0; + break; + case 2: // release this proxy + cli_proxy_release(proxy); + *uno_exc = 0; + break; + default: // arbitrary method call + { + typelib_InterfaceMethodTypeDescription * method_td = + (typelib_InterfaceMethodTypeDescription *)member_td; + OUString const& usMethodName= *(rtl_uString**) & + ((typelib_InterfaceMemberTypeDescription*) member_td) + ->pMemberName; + + sr::MethodInfo* info = proxy->getMethodInfo(function_pos, + usMethodName, CliProxy::MK_METHOD); + bridge->call_cli( + proxy->m_cliI, + info, + method_td->pReturnTypeRef, method_td->pParams, + method_td->nParams, + uno_ret, uno_args, uno_exc); + return; + } + } + break; + } + default: + { + throw BridgeRuntimeError( + OUSTR("illegal member type description!") ); + } + } + } + catch (BridgeRuntimeError & err) + { + // binary identical struct + ::com::sun::star::uno::RuntimeException exc( + OUSTR("[cli_uno bridge error] ") + err.m_message, + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc); + uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0); +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg(OUStringToOString(exc.Message, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE(0, cstr_msg.getStr()); +#endif + } +} + + + + + -- cgit