Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/cli_ure/source/uno_bridge/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 40 kB image not shown  

Impressum cli_proxy.cxx   Sprache: C

 
/* -*- 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 ) noexcept;

void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) noexcept;

void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) noexcept;

void SAL_CALL cli_proxy_dispatch(
    uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
    void * uno_ret, void * uno_args[], uno_Any ** uno_exc ) noexcept;


}

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_castvoid ** >( &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 );
        assert(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]);
            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 ) noexcept
{
    cli_uno::CliProxy * cliProxy = reinterpret_cast<
        cli_uno::CliProxy * >( proxy );

    delete cliProxy;
}

extern "C"
void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) noexcept
{
    CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
    cliProxy->acquire();
}

extern "C"
void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) noexcept
{
    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 ) noexcept
{
    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* pUnoI2 = bridge->map_cli2uno(
                            proxy->m_cliI, demanded_td.get() );
                        uno_any_construct(
                            (uno_Any *)uno_ret, &pUnoI2, demanded_td.get(), 0 );
                        (*pUnoI2->release)( pUnoI2 );
                    }
                    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: */

94%


¤ Dauer der Verarbeitung: 0.24 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.