diff options
Diffstat (limited to 'cli_ure/source/uno_bridge/cli_proxy.cxx')
-rw-r--r-- | cli_ure/source/uno_bridge/cli_proxy.cxx | 1105 |
1 files changed, 1105 insertions, 0 deletions
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 000000000..22c478177 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.cxx @@ -0,0 +1,1105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "typelib/typedescription.h" +#include "rtl/ustrbuf.hxx" +#include <sal/log.hxx> +#include "com/sun/star/uno/RuntimeException.hpp" +#include "cli_proxy.h" +#include "cli_base.h" +#include "cli_bridge.h" + +#using <cli_ure.dll> +#using <cli_uretypes.dll> + +namespace sr = System::Reflection; +namespace st = System::Text; +namespace sc = System::Collections; +namespace srrm = System::Runtime::Remoting::Messaging; +namespace srr = System::Runtime::Remoting; +namespace srrp = System::Runtime::Remoting::Proxies; +namespace sd = System::Diagnostics; +namespace ucss = unoidl::com::sun::star; + +using namespace cli_uno; + +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<typelib_TypeDescription*>(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) + { + throw BridgeRuntimeError("cannot make type complete: " + OUString::unacquired(& m_typeDesc->aBase.pTypeName)); + } + } +} + +UnoInterfaceInfo::~UnoInterfaceInfo() ///< IDisposable UnoInterfaceInfo::Dispose() +{ + this->!UnoInterfaceInfo(); // call finalizer +} + +UnoInterfaceInfo::!UnoInterfaceInfo() ///< UnoInterfaceInfo::Finalize() +{ + //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<typelib_TypeDescription*>(m_typeDesc)); +} + +UnoInterfaceProxy::UnoInterfaceProxy( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const OUString& oid ) + :RealProxy(MarshalByRefObject::typeid), + 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 = gcnew ArrayList(10); + m_numUnoIfaces = 0; + m_listAdditionalProxies = gcnew 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() ///< IDisposable UnoInterfaceProxy::Dispose() +{ + this->!UnoInterfaceProxy(); // call finalizer +} + +UnoInterfaceProxy::!UnoInterfaceProxy() ///< UnoInterfaceProxy::Finalize() +{ +#if OSL_DEBUG_LEVEL >= 2 + sd::Trace::WriteLine(System::String::Format( + gcnew System::String("cli uno bridge: Destroying proxy " + "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= + gcnew 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<UnoInterfaceInfo^>( + enumInfos->Current); + if (typelib_typedescription_equals( + reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc), + reinterpret_cast<typelib_TypeDescription*>(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(gcnew UnoInterfaceInfo(m_bridge, pUnoI, pTd)); + m_numUnoIfaces = m_listIfaces->Count; +#if OSL_DEBUG_LEVEL >= 2 + System::String^ sInterfaceName = static_cast<UnoInterfaceInfo^>( + m_listIfaces[m_numUnoIfaces - 1])->m_type->FullName; + sd::Trace::WriteLine(System::String::Format( + gcnew System::String("cli uno bridge: Creating proxy for uno object, " + "id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName)); + // add to the string that contains all interface names + _numInterfaces++; + OUString _sNewInterface = "\t" + OUString::number(_numInterfaces) + ". " + mapCliString(sInterfaceName) + "\n"; + pin_ptr<rtl_uString *> 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 == System::Object::typeid) // trivial case + return true; + + System::Threading::Monitor::Enter(this); + try + { + if (nullptr != findInfo( fromType )) // proxy supports demanded interface + return true; + + //query a 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<UnoInterfaceInfo^>(m_listIfaces[0]); + css::uno::TypeDescription membertd( + reinterpret_cast<typelib_InterfaceTypeDescription*>( + info->m_typeDesc)->ppAllMembers[0]); + array<System::Object^>^ args = gcnew array<System::Object^>(1); + + args[0] = fromType; + uno::Any ^ pAny; + System::Object^ pException = nullptr; + + pAny= static_cast<uno::Any ^>( + m_bridge->call_uno( + info->m_unoI, + membertd.get(), + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pReturnTypeRef, + 1, + ((typelib_InterfaceMethodTypeDescription*) + membertd.get())->pParams, + args, nullptr, &pException) ); + + // handle regular exception from target + OSL_ENSURE( + nullptr == pException, + OUStringToOString( + mapCliString( pException->ToString()), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + if (pAny->Type != void::typeid) // has value? + { + if (nullptr != 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( nullptr != proxy->findInfo( fromType ) ); + m_listAdditionalProxies->Add( proxy ); + m_nlistAdditionalProxies = m_listAdditionalProxies->Count; + OSL_ASSERT( nullptr != findInfo( fromType ) ); + return true; + } + } + } + catch (BridgeRuntimeError& e) + { + (void) e; // avoid warning + OSL_FAIL( + OUStringToOString( + e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (System::Exception^ e) + { + System::String^ msg= gcnew System::String( + "An unexpected CLI exception occurred in " + "UnoInterfaceProxy::CanCastTo(). Original" + "message: \n"); + msg= System::String::Concat(msg, e->Message); + OSL_FAIL( + OUStringToOString( + mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (...) + { + OSL_FAIL( + "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 = nullptr; + System::String^ sMethod = static_cast<System::String^> + (props[m_methodNameString]); + array<System::Object^>^ args = static_cast<array<System::Object^>^>( + props[m_ArgsString]); + if (m_Equals_String->Equals(sMethod)) + { + // Object.Equals + OSL_ASSERT(args->Length == 1); + srrp::RealProxy^ rProxy = srr::RemotingServices::GetRealProxy(args[0]); + bool bDone = false; + if (rProxy) + { + UnoInterfaceProxy^ unoProxy = + dynamic_cast<UnoInterfaceProxy^>(rProxy); + if (unoProxy) + { + bool b = m_oid->Equals(unoProxy->getOid()); + retMethod = b; + bDone = true; + } + } + if (bDone == false) + { + //no proxy or not our proxy, therefore Equals must be false + retMethod = false; + } + } + else if (m_GetHashCode_String->Equals(sMethod)) + { + // Object.GetHashCode + int nHash = m_oid->GetHashCode(); + retMethod = nHash; + } + else if (m_GetType_String->Equals(sMethod)) + { + // Object.GetType + retMethod = System::Object::typeid; + } + else if (m_ToString_String->Equals(sMethod)) + { + // Object.ToString + st::StringBuilder^ sb = gcnew st::StringBuilder(256); +// sb->AppendFormat("Uno object proxy. Implemented interface: {0}" +// ". OID: {1}", m_type->ToString(), m_oid); + sb->AppendFormat("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= gcnew srrm::ReturnMessage( + retMethod, gcnew array<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<UnoInterfaceInfo^>( + m_listIfaces[i]); + if (type->IsAssignableFrom(tmpInfo->m_type)) + return tmpInfo; + } + for ( int i = 0; i < m_nlistAdditionalProxies; ++i ) + { + UnoInterfaceProxy ^ proxy = + static_cast< UnoInterfaceProxy ^ >( + m_listAdditionalProxies[ i ] ); + UnoInterfaceInfo ^ info = proxy->findInfo( type ); + if (nullptr != info) + return info; + } + return nullptr; +} + +srrm::IMessage^ UnoInterfaceProxy::Invoke(srrm::IMessage^ callmsg) +{ + try + { + sc::IDictionary^ props= callmsg->Properties; + srrm::LogicalCallContext^ context= + static_cast<srrm::LogicalCallContext^>( + props[m_CallContextString]); + srrm::IMethodCallMessage^ mcm= + static_cast<srrm::IMethodCallMessage^>(callmsg); + + //Find out which UNO interface is being called + System::String^ sTypeName = static_cast<System::String^>( + props[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( nullptr != info ); + + // ToDo do without string conversion, an OUString is not needed here + // get the type description of the call + OUString usMethodName(mapCliString(static_cast<System::String^>( + props[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 + // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>) + 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(); + + array<System::Object^>^ args = static_cast<array<System::Object^>^>( + props[m_ArgsString]); + array<System::Type^>^ argTypes = static_cast<array<System::Type^>^>( + props[m_methodSignatureString]); + System::Object^ pExc = nullptr; + 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); + } + } + 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 = nullptr; + System::Object^ cli_ret= m_bridge->call_uno( + info->m_unoI, member_td.get(), + attribute_td->pAttributeTypeRef, + 0, 0, + nullptr, nullptr, &pExc); + return constructReturnMessage(cli_ret, nullptr, 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; + + array<System::Object^>^ args = + static_cast<array<System::Object^>^>( + props[m_ArgsString]); + System::Object^ pExc = nullptr; + m_bridge->call_uno( + info->m_unoI, member_td.get(), + cppu::UnoType<void>::get().getTypeLibType(), + 1, ¶m, args, nullptr, &pExc); + return constructReturnMessage(nullptr, nullptr, NULL, + callmsg, pExc); + } + else + { + return constructReturnMessage(nullptr, nullptr, NULL, + callmsg, nullptr); + } + } + break; + } + } + } + // ToDo check if the message of the exception is not crippled + // the thing that should not be... no method info found! + throw BridgeRuntimeError("[cli_uno bridge]calling undeclared function on interface " + + OUString::unacquired(& ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName) + + ": " + usMethodName); + } + catch (BridgeRuntimeError & err) + { + srrm::IMethodCallMessage^ mcm = + static_cast<srrm::IMethodCallMessage^>(callmsg); + return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException( + mapUnoString(err.m_message.pData), nullptr), mcm); + } + catch (System::Exception^ e) + { + st::StringBuilder ^ sb = gcnew st::StringBuilder(512); + sb->Append(gcnew System::String( + "An unexpected CLI exception occurred in " + "UnoInterfaceProxy::Invoke. Original" + "message: \n")); + sb->Append(e->Message); + sb->Append((__wchar_t) '\n'); + sb->Append(e->StackTrace); + srrm::IMethodCallMessage^ mcm = + static_cast<srrm::IMethodCallMessage^>(callmsg); + return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException( + sb->ToString(), nullptr), mcm); + } + catch (...) + { + System::String^ msg = gcnew System::String( + "An unexpected native C++ exception occurred in " + "UnoInterfaceProxy::Invoke."); + srrm::IMethodCallMessage^ mcm = + static_cast<srrm::IMethodCallMessage^>(callmsg); + return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException( + msg, nullptr), mcm); + } + return nullptr; +} +/** 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, + array<System::Object^>^ args, + typelib_InterfaceMethodTypeDescription* mtd, + srrm::IMessage^ msg, System::Object^ exc) +{ + srrm::IMessage ^ retVal= nullptr; + srrm::IMethodCallMessage^ mcm = static_cast<srrm::IMethodCallMessage^>(msg); + if (exc) + { + retVal = gcnew srrm::ReturnMessage( + dynamic_cast<System::Exception^>(exc), mcm); + } + else + { + sc::IDictionary^ props= msg->Properties; + srrm::LogicalCallContext^ context= + static_cast<srrm::LogicalCallContext^>( + props[m_CallContextString]); + if (args != nullptr) + { + // Method + //build the array of out parameters, allocate max length + array<System::Object^>^ arOut= gcnew array<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= gcnew srrm::ReturnMessage(cliReturn, arOut, nOut, + context, mcm); + } + else + { + // Attribute (getXXX) + retVal= gcnew srrm::ReturnMessage(cliReturn, nullptr, 0, + context, mcm); + } + } + return retVal; +} + + +CliProxy::CliProxy(Bridge const* bridge, System::Object^ cliI, + typelib_TypeDescription const* td, + const OUString& usOid): + m_ref(1), + m_bridge(bridge), + m_cliI(cliI), + m_unoType(const_cast<typelib_TypeDescription*>(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( + gcnew System::String("cli uno bridge: Creating proxy for cli object, " + "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->IsInterface == false) + return; + array<sr::MethodInfo^>^ arThisMethods = m_type->GetMethods(); + //get the inherited interfaces + array<System::Type^>^ arInheritedIfaces = m_type->GetInterfaces(); + m_nInheritedInterfaces = arInheritedIfaces->Length; + //array containing the number of methods for the interface and its + //inherited interfaces + m_arInterfaceMethodCount = gcnew array<int^>(m_nInheritedInterfaces + 1); + //determine the number of all interface methods, including the inherited + //interfaces + int numMethods = arThisMethods->Length; + for (int i= 0; i < m_nInheritedInterfaces; i++) + { + numMethods += arInheritedIfaces[i]->GetMethods()->Length; + } + //array containing MethodInfos of the cli object + m_arMethodInfos = gcnew array<sr::MethodInfo^>(numMethods); + //array containing MethodInfos of the interface + m_arInterfaceMethodInfos = gcnew array<sr::MethodInfo^>(numMethods); + //array containing the mapping of Uno interface pos to pos in + //m_arMethodInfos + m_arUnoPosToCliPos = gcnew array<System::Int32>(numMethods); + // initialize with -1 + for (int i = 0; i < numMethods; i++) + m_arUnoPosToCliPos[i] = -1; + + //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->Length; + for (;nArLength > 0; nArLength--) + { + sr::InterfaceMapping mapInherited = objType->GetInterfaceMap( + arInheritedIfaces[nArLength - 1]); + int numMethods = mapInherited.TargetMethods->Length; + m_arInterfaceMethodCount[nArLength - 1] = numMethods; + for (int i = 0; i < numMethods; i++, index++) + { + m_arMethodInfos[index] = safe_cast<sr::MethodInfo^>( + mapInherited.TargetMethods[i]); + + m_arInterfaceMethodInfos[index] = safe_cast<sr::MethodInfo^>( + mapInherited.InterfaceMethods[i]); + } + } + //At last come the methods of the furthest derived interface + sr::InterfaceMapping map = objType->GetInterfaceMap(m_type); + nArLength = map.TargetMethods->Length; + m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength; + for (int i = 0; i < nArLength; i++,index++) + { + m_arMethodInfos[index]= safe_cast<sr::MethodInfo^>( + map.TargetMethods[i]); + m_arInterfaceMethodInfos[index]= safe_cast<sr::MethodInfo^>( + map.InterfaceMethods[i]); + } + } + catch (System::InvalidCastException^ ) + { + throw BridgeRuntimeError("[cli_uno bridge] preparing proxy for cli interface: " + mapCliString(m_type->ToString()) + " \nfailed!"); + } +} + +sr::MethodInfo^ CliProxy::getMethodInfo(int nUnoFunctionPos, + const OUString& usMethodName, MethodKind methodKind) +{ + sr::MethodInfo^ ret = nullptr; + //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<System::String^>(Constants::sAttributeSet), + sMethodName); + break; + case MK_GET: + sMethodName = System::String::Concat( + const_cast<System::String^>(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->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) + { + throw BridgeRuntimeError("[cli_uno bridge] CliProxy::getMethodInfo():cli object does not implement interface method: " + usMethodName); + } + 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( + gcnew System::String( + "cli uno bridge: Destroying proxy for cli object, " + "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 OUString& ousOid) +{ + uno_Interface* proxy= static_cast<uno_Interface*>( + new CliProxy(bridge, cliI, pTD, ousOid)); + + //register proxy with target environment (uno) + (*bridge->m_uno_env->registerProxyInterface)( + bridge->m_uno_env, + reinterpret_cast<void**>(&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_atomic_increment( &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_atomic_decrement( &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<typelib_TypeDescriptionReference **>( + uno_args[0])); + if (typelib_TypeClass_INTERFACE + != demanded_td.get()->eTypeClass) + { + throw BridgeRuntimeError( + "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 exception occurred + *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( + "illegal member type description!" ); + } + } + } + catch (BridgeRuntimeError & err) + { + // binary identical struct + css::uno::RuntimeException exc( + "[cli_uno bridge error] " + err.m_message, + css::uno::Reference< + css::uno::XInterface >() ); + css::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get(); + uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0); + SAL_WARN( "cli", exc); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |