| /************************************************************** |
| * |
| * 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_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" |
| |
| #using <mscorlib.dll> |
| #using <cli_ure.dll> |
| #using <cli_uretypes.dll> |
| |
| 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 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<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) |
| { |
| 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<typelib_TypeDescription*>(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<UnoInterfaceInfo*>( |
| enumInfos->Current); |
| #if OSL_DEBUG_LEVEL > 1 |
| System::Type * t1; |
| System::Type * t2; |
| t1 = mapUnoType( |
| reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) ); |
| t2 = mapUnoType( |
| reinterpret_cast<typelib_TypeDescription*>(pTd) ); |
| #endif |
| 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(new UnoInterfaceInfo(m_bridge, pUnoI, pTd)); |
| m_numUnoIfaces = m_listIfaces->Count; |
| #if OSL_DEBUG_LEVEL >= 2 |
| System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>( |
| 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<UnoInterfaceInfo*>(m_listIfaces->get_Item(0)); |
| css::uno::TypeDescription membertd( |
| reinterpret_cast<typelib_InterfaceTypeDescription*>( |
| 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<System::String*> |
| (props->get_Item(m_methodNameString)); |
| System::Object* args[] = static_cast<System::Object*[]>( |
| 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<UnoInterfaceProxy*>(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<UnoInterfaceInfo*>( |
| 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<srrm::LogicalCallContext*>( |
| props->get_Item(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->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<System::String*>( |
| 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 |
| // <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(); |
| |
| System::Object* args[] = static_cast<System::Object*[]>( |
| props->get_Item(m_ArgsString)); |
| System::Type* argTypes[] = static_cast<System::Type*[]>( |
| 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<System::Object*[]>( |
| 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<srrm::IMethodCallMessage*>(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<srrm::IMethodCallMessage*>(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<srrm::IMethodCallMessage*>(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<srrm::IMethodCallMessage*>(msg); |
| if (exc) |
| { |
| retVal = new srrm::ReturnMessage( |
| dynamic_cast<System::Exception*>(exc), mcm); |
| } |
| else |
| { |
| sc::IDictionary* props= msg->get_Properties(); |
| srrm::LogicalCallContext* context= |
| static_cast<srrm::LogicalCallContext*>( |
| 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<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( |
| 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<sr::MethodInfo*>( |
| mapInherited.TargetMethods[i]); |
| |
| m_arInterfaceMethodInfos[index] = __try_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->get_Length(); |
| m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength; |
| for (int i = 0; i < nArLength; i++,index++) |
| { |
| m_arMethodInfos[index]= __try_cast<sr::MethodInfo*>( |
| map.TargetMethods[i]); |
| m_arInterfaceMethodInfos[index]= __try_cast<sr::MethodInfo*>( |
| 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<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->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<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_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<typelib_TypeDescriptionReference **>( |
| 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 |
| } |
| } |
| |
| |
| |
| |
| |