diff options
Diffstat (limited to 'cli_ure/source/uno_bridge')
-rw-r--r-- | cli_ure/source/uno_bridge/README.txt | 20 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/bridge_exports.map | 8 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_base.h | 180 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_bridge.cxx | 369 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_bridge.h | 120 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_data.cxx | 2011 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_environment.cxx | 173 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_environment.h | 114 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_proxy.cxx | 1178 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_proxy.h | 299 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/cli_uno.cxx | 290 | ||||
-rw-r--r-- | cli_ure/source/uno_bridge/makefile.mk | 95 |
12 files changed, 4857 insertions, 0 deletions
diff --git a/cli_ure/source/uno_bridge/README.txt b/cli_ure/source/uno_bridge/README.txt new file mode 100644 index 000000000000..39b3ce3648fe --- /dev/null +++ b/cli_ure/source/uno_bridge/README.txt @@ -0,0 +1,20 @@ +Because of the LoaderLock bug in .NET Framework 1.0 and 1.1 the cli_uno.dll is linked +with the /NOENTRY switch, which prevent that the C-runtime is initialized when loading +the dll. + +Also I removed all static c++ objects which need construction by the CRT, +exception handling seems to need an initialised CRT. Therefore +I added CRT initialization code in uno_initEnvironment (cli_bridge.cxx) +However there is no deinitialization done because bridge libraries remain +in memory until the process dies. There is actually no good place where +this had to be called. If we would do that we would have to implement that +the bridge can be disposed. + + +Sell also: + +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vcconmixeddllloadingproblem.asp +http://support.microsoft.com/?id=814472 +http://www.ddj.com/dept/windows/184416689 +http://blogs.msdn.com/cbrumme/archive/2003/08/20/51504.aspx +http://msdn2.microsoft.com/en-US/library/ms172219.aspx
\ No newline at end of file diff --git a/cli_ure/source/uno_bridge/bridge_exports.map b/cli_ure/source/uno_bridge/bridge_exports.map new file mode 100644 index 000000000000..df39965a2b51 --- /dev/null +++ b/cli_ure/source/uno_bridge/bridge_exports.map @@ -0,0 +1,8 @@ +UDK_3_0_0 { + global: + component_canUnload; + uno_initEnvironment; + uno_ext_getMapping; + local: + *; +}; diff --git a/cli_ure/source/uno_bridge/cli_base.h b/cli_ure/source/uno_bridge/cli_base.h new file mode 100644 index 000000000000..0ff3f40f9762 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_base.h @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_CLI_BASE_H +#define INCLUDED_CLI_BASE_H + +#pragma unmanaged +// Workaround: osl/mutex.h contains only a forward declaration of _oslMutexImpls. +// When using the inline class in Mutex in osl/mutex.hxx, the loader needs to find +// a declaration for the struct. If not found a TypeLoadException is being thrown. +struct _oslMutexImpl +{ +}; +#pragma managed +#include <memory> +#include "rtl/ustring.hxx" +#include "typelib/typedescription.hxx" + +#using <mscorlib.dll> +#using <system.dll> + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +namespace cli_uno +{ +System::Type* loadCliType(System::String * typeName); +System::Type* mapUnoType(typelib_TypeDescription const * pTD); +System::Type* mapUnoType(typelib_TypeDescriptionReference const * pTD); +typelib_TypeDescriptionReference* mapCliType(System::Type* cliType); +rtl::OUString mapCliString(System::String const * data); +System::String* mapUnoString(rtl_uString const * data); +System::String* mapUnoTypeName(rtl_uString const * typeName); + +__gc struct Constants +{ + static const System::String* sXInterfaceName= new System::String( + S"unoidl.com.sun.star.uno.XInterface"); + static const System::String* sObject= new System::String(S"System.Object"); + static const System::String* sType= new System::String(S"System.Type"); + static const System::String* sUnoidl= new System::String(S"unoidl."); + static const System::String* sVoid= new System::String(S"System.Void"); + static const System::String* sAny= new System::String(S"uno.Any"); + static const System::String* sArArray= new System::String(S"System.Array[]"); + static const System::String* sBoolean= new System::String(S"System.Boolean"); + static const System::String* sChar= new System::String(S"System.Char"); + static const System::String* sByte= new System::String(S"System.Byte"); + static const System::String* sInt16= new System::String(S"System.Int16"); + static const System::String* sUInt16= new System::String(S"System.UInt16"); + static const System::String* sInt32= new System::String(S"System.Int32"); + static const System::String* sUInt32= new System::String(S"System.UInt32"); + static const System::String* sInt64= new System::String(S"System.Int64"); + static const System::String* sUInt64= new System::String(S"System.UInt64"); + static const System::String* sString= new System::String(S"System.String"); + static const System::String* sSingle= new System::String(S"System.Single"); + static const System::String* sDouble= new System::String(S"System.Double"); + static const System::String* sArBoolean= new System::String(S"System.Boolean[]"); + static const System::String* sArChar= new System::String(S"System.Char[]"); + static const System::String* sArByte= new System::String(S"System.Byte[]"); + static const System::String* sArInt16= new System::String(S"System.Int16[]"); + static const System::String* sArUInt16= new System::String(S"System.UInt16[]"); + static const System::String* sArInt32= new System::String(S"System.Int32[]"); + static const System::String* sArUInt32= new System::String(S"System.UInt32[]"); + static const System::String* sArInt64= new System::String(S"System.Int64[]"); + static const System::String* sArUInt64= new System::String(S"System.UInt64[]"); + static const System::String* sArString= new System::String(S"System.String[]"); + static const System::String* sArSingle= new System::String(S"System.Single[]"); + static const System::String* sArDouble= new System::String(S"System.Double[]"); + static const System::String* sArType= new System::String(S"System.Type[]"); + static const System::String* sArObject= new System::String(S"System.Object[]"); + static const System::String* sBrackets= new System::String(S"[]"); + static const System::String* sAttributeSet= new System::String(S"set_"); + static const System::String* sAttributeGet= new System::String(S"get_"); + + static const System::String* usXInterface = S"com.sun.star.uno.XInterface"; + static const System::String* usVoid = S"void"; + static const System::String* usType = S"type"; + static const System::String* usAny = S"any"; + static const System::String* usBrackets = S"[]"; + static const System::String* usBool = S"boolean"; + static const System::String* usByte = S"byte"; + static const System::String* usChar = S"char"; + static const System::String* usShort = S"short"; + static const System::String* usUShort = S"unsigned short"; + static const System::String* usLong = S"long"; + static const System::String* usULong = S"unsigned long"; + static const System::String* usHyper = S"hyper"; + static const System::String* usUHyper = S"unsigned hyper"; + static const System::String* usString = S"string"; + static const System::String* usFloat = S"float"; + static const System::String* usDouble = S"double"; +}; + +struct BridgeRuntimeError +{ + ::rtl::OUString m_message; + + inline BridgeRuntimeError( ::rtl::OUString const & message ) + : m_message( message ) + {} +}; + +//================================================================================================== +struct rtl_mem +{ + inline static void * operator new ( size_t nSize ) + { return rtl_allocateMemory( nSize ); } + inline static void operator delete ( void * mem ) + { if (mem) rtl_freeMemory( mem ); } + inline static void * operator new ( size_t, void * mem ) + { return mem; } + inline static void operator delete ( void *, void * ) + {} + + static inline ::std::auto_ptr< rtl_mem > allocate( ::std::size_t bytes ); +}; +//-------------------------------------------------------------------------------------------------- +inline ::std::auto_ptr< rtl_mem > rtl_mem::allocate( ::std::size_t bytes ) +{ + void * p = rtl_allocateMemory( bytes ); + if (0 == p) + throw BridgeRuntimeError(OUSTR("out of memory!") ); + return ::std::auto_ptr< rtl_mem >( (rtl_mem *)p ); +} + +//================================================================================================== +class TypeDescr +{ + typelib_TypeDescription * m_td; + + TypeDescr( TypeDescr & ); // not impl + void operator = ( TypeDescr ); // not impl + +public: + inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref ); + inline ~TypeDescr() SAL_THROW( () ) + { TYPELIB_DANGER_RELEASE( m_td ); } + + inline typelib_TypeDescription * get() const + { return m_td; } +}; + +inline TypeDescr::TypeDescr( typelib_TypeDescriptionReference * td_ref ) + : m_td( 0 ) +{ + TYPELIB_DANGER_GET( &m_td, td_ref ); + if (0 == m_td) + { + throw BridgeRuntimeError( + OUSTR("cannot get comprehensive type description for ") + + *reinterpret_cast< ::rtl::OUString const * >( &td_ref->pTypeName ) ); + } +} + + +} //end namespace cli_uno + #endif diff --git a/cli_ure/source/uno_bridge/cli_bridge.cxx b/cli_ure/source/uno_bridge/cli_bridge.cxx new file mode 100644 index 000000000000..ab78b2f9d95b --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_bridge.cxx @@ -0,0 +1,369 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include <vcclr.h> +//ToDo: remove when build with .NET 2 +#pragma warning(push, 1) +#include <windows.h> +#include "uno/environment.hxx" +#pragma warning(pop) +#include "rtl/unload.h" +#include "uno/lbnames.h" +#include "uno/mapping.hxx" +#include "typelib/typedescription.hxx" +#include "rtl/ustring.hxx" + +#include "cli_bridge.h" +#include "cli_proxy.h" +namespace srr= System::Runtime::Remoting; +namespace srrp= System::Runtime::Remoting::Proxies; +#using <mscorlib.dll> +#if defined(_MSC_VER) && (_MSC_VER < 1400) +#include <_vcclrit.h> +#endif + +namespace cssu= com::sun::star::uno; + + +namespace sri= System::Runtime::InteropServices; +using namespace rtl; + +namespace cli_uno +{ + +extern "C" +{ +void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping const * that = static_cast< Mapping const * >( mapping ); + that->m_bridge->acquire(); +} +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_release( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping const * that = static_cast< Mapping const * >( mapping ); + that->m_bridge->release(); +} + + +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_cli2uno( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + uno_Interface ** ppUnoI = (uno_Interface **)ppOut; + intptr_t cliI = (intptr_t)pIn; + + OSL_ENSURE( ppUnoI && td, "### null ptr!" ); + + if (0 != *ppUnoI) + { + uno_Interface * pUnoI = *(uno_Interface **)ppUnoI; + (*pUnoI->release)( pUnoI ); + *ppUnoI = 0; + } + try + { + Mapping const * that = static_cast< Mapping const * >( mapping ); + Bridge * bridge = that->m_bridge; + + if (0 != cliI) + { + System::Object* cliObj= sri::GCHandle::op_Explicit(cliI).Target; + (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg( + OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } +} +//-------------------------------------------------------------------------------------------------- +void SAL_CALL Mapping_uno2cli( + uno_Mapping * mapping, void ** ppOut, + void * pIn, typelib_InterfaceTypeDescription * td ) + SAL_THROW_EXTERN_C() +{ + try + { + OSL_ENSURE( td && ppOut, "### null ptr!" ); + OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode)) + && (sizeof(System::Boolean) == sizeof(sal_Bool)) + && (sizeof(System::SByte) == sizeof(sal_Int8)) + && (sizeof(System::Int16) == sizeof(sal_Int16)) + && (sizeof(System::UInt16) == sizeof(sal_uInt16)) + && (sizeof(System::Int32) == sizeof(sal_Int32)) + && (sizeof(System::UInt32) == sizeof(sal_uInt32)) + && (sizeof(System::Int64) == sizeof(sal_Int64)) + && (sizeof(System::UInt64) == sizeof(sal_uInt64)) + && (sizeof(System::Single) == sizeof(float)) + && (sizeof(System::Double) == sizeof(double)), + "[cli_uno bridge] incompatible .NET data types"); + intptr_t * ppDNetI = (intptr_t *)ppOut; + uno_Interface * pUnoI = (uno_Interface *)pIn; + + Mapping const * that = static_cast< Mapping const * >( mapping ); + Bridge * bridge = that->m_bridge; + + if (0 != *ppDNetI) + { + sri::GCHandle::op_Explicit(ppDNetI).Free(); + } + + if (0 != pUnoI) + { + System::Object* cliI= bridge->map_uno2cli(pUnoI, td); + intptr_t ptr= NULL; + if(cliI) + { + ptr= sri::GCHandle::op_Explicit(sri::GCHandle::Alloc(cliI)) +#ifdef _WIN32 + .ToInt32(); +#else /* defined(_WIN64) */ .ToInt64(); +#endif + } + (*ppOut)= reinterpret_cast<void*>(ptr); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + rtl::OString cstr_msg( + rtl::OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } +} + +//__________________________________________________________________________________________________ +void SAL_CALL Bridge_free( uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + Mapping * that = static_cast< Mapping * >( mapping ); + delete that->m_bridge; +} + +} //extern C +} //namespace + +namespace cli_uno +{ + +//__________________________________________________________________________________________________ +/** ToDo + I doubt that the the case that the ref count raises from 0 to 1 + can occur. uno_ext_getMapping returns an acquired mapping. Every time + that function is called then a new mapping is created. Following the + rules of ref counted objects, then if the ref count is null noone has + a reference to the object anymore. Hence noone can call acquire. If someone + calls acquire then they must have kept an unacquired pointer which is + illegal. + */ +void Bridge::acquire() const SAL_THROW( () ) +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + if (m_registered_cli2uno) + { + uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno); + uno_registerMapping( + & const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 ); + } + else + { + uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli); + uno_registerMapping( + &mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 ); + } + } +} +//__________________________________________________________________________________________________ +void Bridge::release() const SAL_THROW( () ) +{ + if (! osl_decrementInterlockedCount( &m_ref )) + { + uno_revokeMapping( + m_registered_cli2uno + ? const_cast<Mapping*>(&m_cli2uno) + : const_cast<Mapping*>(&m_uno2cli) ); + } +} +//__________________________________________________________________________________________________ +Bridge::Bridge( + uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env, + bool registered_cli2uno ) + : m_ref( 1 ), + m_uno_env( uno_env ), + m_uno_cli_env( uno_cli_env ), + m_registered_cli2uno( registered_cli2uno ) +{ + OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env ); + (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); + (*m_uno_cli_env->acquire)( m_uno_cli_env ); + + // cli2uno + m_cli2uno.acquire = Mapping_acquire; + m_cli2uno.release = Mapping_release; + m_cli2uno.mapInterface = Mapping_cli2uno; + m_cli2uno.m_bridge = this; + // uno2cli + m_uno2cli.acquire = Mapping_acquire; + m_uno2cli.release = Mapping_release; + m_uno2cli.mapInterface = Mapping_uno2cli; + m_uno2cli.m_bridge = this; + +} + +//__________________________________________________________________________________________________ +Bridge::~Bridge() SAL_THROW( () ) +{ + //System::GC::Collect(); + (*m_uno_cli_env->release)( m_uno_cli_env ); + (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); +} + + + +} //namespace cli_uno + +extern "C" +{ + +namespace cli_uno +{ +//-------------------------------------------------------------------------------------------------- +void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env ) + SAL_THROW_EXTERN_C() +{ + uno_cli_env->pContext = 0; +} + +//################################################################################################## +void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env ) + SAL_THROW_EXTERN_C() +{ + //ToDo: remove when compiled with .NET 2 +#if defined(_MSC_VER) && (_MSC_VER < 1400) + __crt_dll_initialize(); +#endif + + uno_cli_env->environmentDisposing= cli_env_disposing; + uno_cli_env->pExtEnv = 0; + //Set the console to print Trace messages +#if OSL_DEBUG_LEVEL >= 1 + System::Diagnostics::Trace::get_Listeners()-> + Add( new System::Diagnostics::TextWriterTraceListener(System::Console::get_Out())); +#endif + OSL_ASSERT( 0 == uno_cli_env->pContext ); + + // We let the Cli_environment leak, since there is no good point where we could destruct it. + //dispose is not used because we would have then also synchronize the calls to proxies. If the + //Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points + //where g_cli_env is accessed. + //When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot + //member in a unmanaged class, such as Bridge. + CliEnvHolder::g_cli_env = new Cli_environment(); +} +//################################################################################################## +void SAL_CALL uno_ext_getMapping( + uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) + SAL_THROW_EXTERN_C() +{ + OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo ); + if (*ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + *ppMapping = 0; + } + + + OUString const & from_env_typename = *reinterpret_cast< OUString const * >( + &pFrom->pTypeName ); + OUString const & to_env_typename = *reinterpret_cast< OUString const * >( + &pTo->pTypeName ); + + uno_Mapping * mapping = 0; + + try + { + if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ) && + to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) )) + { + Bridge * bridge = new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1 + mapping = &bridge->m_cli2uno; + uno_registerMapping( + &mapping, Bridge_free, pFrom, (uno_Environment *)pTo->pExtEnv, 0 ); + } + else if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) && + to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) )) + { + Bridge * bridge = new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1 + mapping = &bridge->m_uno2cli; + uno_registerMapping( + &mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 ); + } + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL >= 1 + OString cstr_msg( + OUStringToOString( + OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } + *ppMapping = mapping; +} + + +//################################################################################################## +sal_Bool SAL_CALL component_canUnload( TimeValue * ) + SAL_THROW_EXTERN_C() +{ + return true; +} + +} +} diff --git a/cli_ure/source/uno_bridge/cli_bridge.h b/cli_ure/source/uno_bridge/cli_bridge.h new file mode 100644 index 000000000000..1bc3a926519e --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_bridge.h @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_CLI_BRIDGE_H +#define INCLUDED_CLI_BRIDGE_H +#include <vcclr.h> +#include "osl/interlck.h" +#include "uno/mapping.h" +#include "uno/environment.h" +#include "uno/dispatcher.h" +#include "cli_base.h" +#include "cli_environment.h" +#using <mscorlib.dll> +//#using <cli_uretypes.dll> +#using <cli_basetypes.dll> +#using <system.dll> + +namespace sr = System::Reflection; + +namespace cli_uno +{ + + +//==== holds environments and mappings ============================================================= +struct Bridge; +struct Mapping : public uno_Mapping +{ + Bridge* m_bridge; +}; + +// The environment will be created in uno_initEnvironment. See also the remarks there +//Managed cli environment for cli objects an UNO proxies (which are cli +//objects. The uno_Environment is not used for cli objects. +__gc struct CliEnvHolder { +static Cli_environment * g_cli_env = NULL; +}; + +//================================================================================================== +/** An instance of Bridge represents exactly one mapping therefore either + m_cli2uno or m_uno2cli is valid. +*/ +struct Bridge +{ + mutable oslInterlockedCount m_ref; + uno_ExtEnvironment * m_uno_env; + uno_Environment * m_uno_cli_env; + + Mapping m_cli2uno; + Mapping m_uno2cli; + bool m_registered_cli2uno; + + ~Bridge() SAL_THROW( () ); + Bridge( uno_Environment * java_env, uno_ExtEnvironment * uno_env, bool registered_java2uno ); + + void acquire() const; + void release() const; + + void map_to_uno( + void * uno_data, System::Object* cli_data, + typelib_TypeDescriptionReference * type, + bool assign) const; + + /** + @param info + the type of the converted data. It may be a byref type. + */ + void map_to_cli( + System::Object* *cli_data, void const * uno_data, + typelib_TypeDescriptionReference * type, System::Type* info /* maybe 0 */, + bool bDontCreateObj) const; + + System::Object* map_uno2cli(uno_Interface * pUnoI, typelib_InterfaceTypeDescription* pTD) const; + + System::Object* Bridge::call_uno(uno_Interface * pUnoI, + typelib_TypeDescription* member_td, + typelib_TypeDescriptionReference * return_type, + sal_Int32 nParams, typelib_MethodParameter const * pParams, + System::Object * args[], System::Type* argTypes[], + System::Object** pException) const; + + + void call_cli( + System::Object* cliI, sr::MethodInfo* method, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, int nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const; + + uno_Interface * map_cli2uno( + System::Object* cliI, typelib_TypeDescription* pTD) const; + +}; + +} //namespace cli_uno + + +#endif diff --git a/cli_ure/source/uno_bridge/cli_data.cxx b/cli_ure/source/uno_bridge/cli_data.cxx new file mode 100644 index 000000000000..99f4bda82563 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_data.cxx @@ -0,0 +1,2011 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#pragma warning(push, 1) +#include "windows.h" +#pragma warning(pop) + +#include <memory> + + +#include "rtl/ustring.hxx" +#include "rtl/ustrbuf.hxx" +#include "uno/sequence2.h" +#include "typelib/typedescription.hxx" +#include "cli_proxy.h" +#include "cli_base.h" +#include "cli_bridge.h" + +#using <cli_uretypes.dll> + + +#undef VOID + +namespace css = com::sun::star; + +namespace sri = System::Runtime::InteropServices; +namespace sr = System::Reflection; +namespace st = System::Text; +namespace ucss = unoidl::com::sun::star; + +using namespace rtl; +using namespace std; + + +namespace cli_uno +{ +System::String* mapUnoPolymorphicName(System::String* unoName); +OUString mapCliTypeName(System::String* typeName); +System::String* mapCliPolymorphicName(System::String* unoName); +System::String* mapPolymorphicName(System::String* unoName, bool bCliToUno); + +inline auto_ptr< rtl_mem > seq_allocate( sal_Int32 nElements, sal_Int32 nSize ) +{ + auto_ptr< rtl_mem > seq( + rtl_mem::allocate( SAL_SEQUENCE_HEADER_SIZE + (nElements * nSize) ) ); + uno_Sequence * p = (uno_Sequence *)seq.get(); + p->nRefCount = 1; + p->nElements = nElements; + return seq; +} + + +System::Object* Bridge::map_uno2cli(uno_Interface * pUnoI, typelib_InterfaceTypeDescription *pTD) const +{ + System::Object* retVal= NULL; +// get oid + rtl_uString * pOid = 0; + (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI ); + OSL_ASSERT( 0 != pOid ); + OUString oid(pOid, SAL_NO_ACQUIRE); + + //see if the interface was already mapped + System::Type* ifaceType= mapUnoType(reinterpret_cast<typelib_TypeDescription*>(pTD)); + System::String* sOid= mapUnoString(oid.pData); + + System::Threading::Monitor::Enter( CliEnvHolder::g_cli_env ); + try + { + retVal = CliEnvHolder::g_cli_env->getRegisteredInterface(sOid, ifaceType); + if (retVal) + { + // There is already an registered object. It can either be a proxy + // for the UNO object or a real cli object. In the first case we + // tell the proxy that it shall also represent the current UNO + // interface. If it already does that, then it does nothing + if (srr::RemotingServices::IsTransparentProxy(retVal)) + { + UnoInterfaceProxy* p = static_cast<UnoInterfaceProxy*>( + srr::RemotingServices::GetRealProxy(retVal)); + p->addUnoInterface(pUnoI, pTD); + } + } + else + { + retVal = UnoInterfaceProxy::create( + (Bridge *) this, pUnoI, pTD, oid ); + } + } + __finally + { + System::Threading::Monitor::Exit( CliEnvHolder::g_cli_env ); + } + + return retVal; +} + +uno_Interface* Bridge::map_cli2uno(System::Object* cliObj, typelib_TypeDescription *pTD) const +{ + uno_Interface* retIface = NULL; + // get oid from dot net environment + System::String* ds_oid = CliEnvHolder::g_cli_env->getObjectIdentifier( cliObj); + OUString ousOid = mapCliString(ds_oid); + // look if interface is already mapped + m_uno_env->getRegisteredInterface(m_uno_env, (void**) &retIface, ousOid.pData, + (typelib_InterfaceTypeDescription*) pTD); + if ( ! retIface) + { + System::Threading::Monitor::Enter(__typeof(Cli_environment)); + try + { + m_uno_env->getRegisteredInterface(m_uno_env, (void**) &retIface, ousOid.pData, + (typelib_InterfaceTypeDescription*) pTD); + if ( ! retIface) + { + retIface = CliProxy::create((Bridge*)this, cliObj, pTD, ousOid); + } + } + __finally + { + System::Threading::Monitor::Exit(__typeof(Cli_environment)); + } + } + return retIface; +} + +inline System::Type* loadCliType(rtl_uString * unoName) +{ + return loadCliType(mapUnoTypeName(unoName)); +} + +System::Type* loadCliType(System::String * unoName) +{ + System::Type* retVal= NULL; + try + { + //If unoName denotes a polymorphic type, e.g com.sun.star.beans.Defaulted<System.Char> + //then we remove the type list, otherwise the type could not be loaded. + bool bIsPolymorphic = false; + + System::String * loadName = unoName; + int index = unoName->IndexOf('<'); + if (index != -1) + { + loadName = unoName->Substring(0, index); + bIsPolymorphic = true; + } + System::AppDomain* currentDomain = System::AppDomain::CurrentDomain; + sr::Assembly* assems[] = currentDomain->GetAssemblies(); + for (int i = 0; i < assems->Length; i++) + { + retVal = assems[i]->GetType(loadName, false); + if (retVal) + break; + } + + if (retVal == NULL) + { + System::String * msg = new System::String(S"A type could not be loaded: "); + msg = System::String::Concat(msg, loadName); + throw BridgeRuntimeError(mapCliString(msg)); + } + + if (bIsPolymorphic) + { + retVal = uno::PolymorphicType::GetType(retVal, unoName); + } + } + catch( System::Exception * e) + { + rtl::OUString ouMessage(mapCliString(e->get_Message())); + throw BridgeRuntimeError(ouMessage); + } + return retVal; +} + + +System::Type* mapUnoType(typelib_TypeDescription const * pTD) +{ + return mapUnoType(pTD->pWeakRef); +} + +System::Type* mapUnoType(typelib_TypeDescriptionReference const * pTD) +{ + System::Type * retVal = 0; + switch (pTD->eTypeClass) + { + case typelib_TypeClass_VOID: + retVal= __typeof(void); break; + case typelib_TypeClass_CHAR: + retVal= __typeof(System::Char); break; + case typelib_TypeClass_BOOLEAN: + retVal= __typeof(System::Boolean); break; + case typelib_TypeClass_BYTE: + retVal= __typeof(System::Byte); break; + case typelib_TypeClass_SHORT: + retVal= __typeof(System::Int16); break; + case typelib_TypeClass_UNSIGNED_SHORT: + retVal= __typeof(System::UInt16); break; + case typelib_TypeClass_LONG: + retVal= __typeof(System::Int32); break; + case typelib_TypeClass_UNSIGNED_LONG: + retVal= __typeof(System::UInt32); break; + case typelib_TypeClass_HYPER: + retVal= __typeof(System::Int64); break; + case typelib_TypeClass_UNSIGNED_HYPER: + retVal= __typeof(System::UInt64); break; + case typelib_TypeClass_FLOAT: + retVal= __typeof(System::Single); break; + case typelib_TypeClass_DOUBLE: + retVal= __typeof(System::Double); break; + case typelib_TypeClass_STRING: + retVal= __typeof(System::String); break; + case typelib_TypeClass_TYPE: + retVal= __typeof(System::Type); break; + case typelib_TypeClass_ANY: + retVal= __typeof(uno::Any); break; + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + retVal= loadCliType(pTD->pTypeName); break; + case typelib_TypeClass_INTERFACE: + { + //special handling for XInterface, since it does not exist in cli. + rtl::OUString usXInterface(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XInterface")); + if (usXInterface.equals(pTD->pTypeName)) + retVal= __typeof(System::Object); + else + retVal= loadCliType(pTD->pTypeName); + break; + } + case typelib_TypeClass_SEQUENCE: + { + css::uno::TypeDescription seqType( + const_cast<typelib_TypeDescriptionReference*>(pTD)); + typelib_TypeDescriptionReference* pElementTDRef= + reinterpret_cast<typelib_IndirectTypeDescription*>(seqType.get())->pType; + switch (pElementTDRef->eTypeClass) + { + case typelib_TypeClass_CHAR: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArChar)); break; + case typelib_TypeClass_BOOLEAN: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArBoolean)); + break; + case typelib_TypeClass_BYTE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArByte)); + break; + case typelib_TypeClass_SHORT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt16)); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt16)); + break; + case typelib_TypeClass_LONG: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt32)); + break; + case typelib_TypeClass_UNSIGNED_LONG: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt32)); + break; + case typelib_TypeClass_HYPER: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArInt64)); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArUInt64)); + break; + case typelib_TypeClass_FLOAT: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArSingle)); + break; + case typelib_TypeClass_DOUBLE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArDouble)); + break; + case typelib_TypeClass_STRING: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArString)); + break; + case typelib_TypeClass_TYPE: + retVal= System::Type::GetType(const_cast<System::String*>(Constants::sArType)); + break; + case typelib_TypeClass_ANY: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_SEQUENCE: + { + retVal= loadCliType(pTD->pTypeName); + break; + } + default: + //All cases should be handled by the case statements above + OSL_ASSERT(0); + break; + } + break; + } + default: + OSL_ASSERT(false); + break; + } + return retVal; +} + +/** Returns an acquired td. + */ +typelib_TypeDescriptionReference* mapCliType(System::Type* cliType) +{ + typelib_TypeDescriptionReference* retVal= NULL; + if (cliType == NULL) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_VOID ); + typelib_typedescriptionreference_acquire( retVal ); + return retVal; + } + //check for Enum first, + //because otherwise case System::TypeCode::Int32 applies + if (cliType->get_IsEnum()) + { + OUString usTypeName= mapCliTypeName(cliType->get_FullName()); + css::uno::Type unoType(css::uno::TypeClass_ENUM, usTypeName); + retVal= unoType.getTypeLibType(); + typelib_typedescriptionreference_acquire(retVal); + } + else + { + switch (System::Type::GetTypeCode(cliType)) + { + case System::TypeCode::Boolean: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_BOOLEAN ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Char: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_CHAR ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Byte: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_BYTE ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int16: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_SHORT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int32: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_LONG ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Int64: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_HYPER ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt16: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_SHORT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt32: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_LONG ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::UInt64: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_UNSIGNED_HYPER ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Single: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_FLOAT ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::Double: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_DOUBLE ); + typelib_typedescriptionreference_acquire( retVal ); + break; + case System::TypeCode::String: + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_STRING ); + typelib_typedescriptionreference_acquire( retVal ); + break; + default: + break; + } + } + if (retVal == NULL) + { + System::String* cliTypeName= cliType->get_FullName(); + // Void + if (const_cast<System::String*>(Constants::sVoid)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_VOID ); + typelib_typedescriptionreference_acquire( retVal ); + } + // Type + else if (const_cast<System::String*>(Constants::sType)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_TYPE ); + typelib_typedescriptionreference_acquire( retVal ); + } + // Any + else if (const_cast<System::String*>(Constants::sAny)->Equals( + cliTypeName)) + { + retVal = * typelib_static_type_getByTypeClass( + typelib_TypeClass_ANY ); + typelib_typedescriptionreference_acquire( retVal ); + } + //struct, interfaces, sequences + else + { + OUString usTypeName; + uno::PolymorphicType * poly = dynamic_cast<uno::PolymorphicType*>(cliType); + if (poly != NULL) + usTypeName = mapCliTypeName( poly->PolymorphicName); + else + usTypeName = mapCliTypeName(cliTypeName); + typelib_TypeDescription* td = NULL; + typelib_typedescription_getByName(&td, usTypeName.pData); + if (td) + { + retVal = td->pWeakRef; + typelib_typedescriptionreference_acquire(retVal); + typelib_typedescription_release(td); + } + } + } + if (retVal == NULL) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("[cli_uno bridge] mapCliType():" + "could not map type: ") ); + buf.append(mapCliString(cliType->get_FullName())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + return retVal; +} + +/** + Otherwise a leading "unoidl." is removed. + */ +System::String* mapUnoTypeName(rtl_uString const * typeName) +{ + OUString usUnoName( const_cast< rtl_uString * >( typeName ) ); + st::StringBuilder* buf= new st::StringBuilder(); + //determine if the type is a sequence and its dimensions + int dims= 0; + if (usUnoName[0] == '[') + { + sal_Int32 index= 1; + while (true) + { + if (usUnoName[index++] == ']') + dims++; + if (usUnoName[index++] != '[') + break; + } + usUnoName = usUnoName.copy(index - 1); + } + System::String * sUnoName = mapUnoString(usUnoName.pData); + if (sUnoName->Equals(const_cast<System::String*>(Constants::usBool))) + buf->Append(const_cast<System::String*>(Constants::sBoolean)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usChar))) + buf->Append(const_cast<System::String*>(Constants::sChar)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usByte))) + buf->Append(const_cast<System::String*>(Constants::sByte)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usShort))) + buf->Append(const_cast<System::String*>(Constants::sInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usUShort))) + buf->Append(const_cast<System::String*>(Constants::sUInt16)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usLong))) + buf->Append(const_cast<System::String*>(Constants::sInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usULong))) + buf->Append(const_cast<System::String*>(Constants::sUInt32)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usHyper))) + buf->Append(const_cast<System::String*>(Constants::sInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usUHyper))) + buf->Append(const_cast<System::String*>(Constants::sUInt64)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usFloat))) + buf->Append(const_cast<System::String*>(Constants::sSingle)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usDouble))) + buf->Append(const_cast<System::String*>(Constants::sDouble)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usString))) + buf->Append(const_cast<System::String*>(Constants::sString)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usVoid))) + buf->Append(const_cast<System::String*>(Constants::sVoid)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usType))) + buf->Append(const_cast<System::String*>(Constants::sType)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usXInterface))) + buf->Append(const_cast<System::String*>(Constants::sObject)); + else if (sUnoName->Equals(const_cast<System::String*>(Constants::usAny))) + { + buf->Append(const_cast<System::String*>(Constants::sAny)); + } + else + { + //put "unoidl." at the beginning + buf->Append(const_cast<System::String*>(Constants::sUnoidl)); + //for polymorphic struct types remove the brackets, e.g mystruct<bool> -> mystruct + System::String * sName = mapUnoPolymorphicName(sUnoName); + buf->Append(sName); + } + // apend [] + for (;dims--;) + buf->Append(const_cast<System::String*>(Constants::sBrackets)); + + return buf->ToString(); +} + + + + +/** For example, there is a uno type + com.sun.star.Foo<char, long>. + The values in the type list + are uno types and are replaced by cli types, such as System.Char, + System.Int32, etc. + The präfix unoidl is not added. + */ +inline System::String* mapUnoPolymorphicName(System::String* unoName) +{ + return mapPolymorphicName(unoName, false); +} +/** For example, there is a type name such as + com.sun.star.Foo<System.Char, System.Int32>. + The values in the type list + are CLI types and are replaced by uno types, such as char, + long, etc. + The präfix unoidl remains. + */ +inline System::String* mapCliPolymorphicName(System::String* unoName) +{ + return mapPolymorphicName(unoName, true); +} + +System::String* mapPolymorphicName(System::String* unoName, bool bCliToUno) +{ + int index = unoName->IndexOf('<'); + if (index == -1) + return unoName; + + System::Text::StringBuilder * builder = new System::Text::StringBuilder(256); + builder->Append(unoName->Substring(0, index +1 )); + + //Find the first occurrence of ',' + //If the parameter is a polymorphic struct then we neede to ignore everything + //between the brackets because it can also contain commas + //get the type list within < and > + int endIndex = unoName->Length - 1; + index++; + int cur = index; + int countParams = 0; + while (cur <= endIndex) + { + System::Char c = unoName->Chars[cur]; + if (c == ',' || c == '>') + { + //insert a comma if needed + if (countParams != 0) + builder->Append(S","); + countParams++; + System::String * sParam = unoName->Substring(index, cur - index); + //skip the comma + cur++; + //the the index to the beginning of the next param + index = cur; + if (bCliToUno) + { + builder->Append(mapCliTypeName(sParam)); + } + else + { + OUString s = mapCliString(sParam); + builder->Append(mapUnoTypeName(s.pData)); + } + } + else if (c == '<') + { + cur++; + //continue until the matching '>' + int numNested = 0; + for (;;cur++) + { + System::Char curChar = unoName->Chars[cur]; + if (curChar == '<') + { + numNested ++; + } + else if (curChar == '>') + { + if (numNested > 0) + numNested--; + else + break; + } + } + } + cur++; + } + + builder->Append((System::Char) '>'); + return builder->ToString(); +} + +OUString mapCliTypeName(System::String* typeName) +{ + int dims= 0; + // Array? determine the "rank" (number of "[]") + // move from the rightmost end to the left, for example + // unoidl.PolymorphicStruct<System.Char[]>[] + // has only a "dimension" of 1 + int cur = typeName->Length - 1; + bool bRightBracket = false; + while (cur >= 0) + { + System::Char c = typeName->Chars[cur]; + if (c == ']') + { + bRightBracket = true; + } + else if (c == '[') + { + if (!bRightBracket) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. No matching brackets for sequence. Name is: ") + + mapCliString(typeName)); + bRightBracket = false; + dims ++; + } + else + { + if (bRightBracket) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. No matching brackets for sequence. Name is: ") + + mapCliString(typeName)); + break; + } + cur--; + } + + if (bRightBracket || cur < 0) + throw BridgeRuntimeError( + OUSTR("Typename is wrong. ") + + mapCliString(typeName)); + + typeName = typeName->Substring(0, cur + 1); + + System::Text::StringBuilder * buf = new System::Text::StringBuilder(512); + + //Put the "[]" at the beginning of the uno type name + for (;dims--;) + buf->Append(const_cast<System::String*>(Constants::usBrackets)); + + if (typeName->Equals(const_cast<System::String*>(Constants::sBoolean))) + buf->Append(const_cast<System::String*>(Constants::usBool)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sChar))) + buf->Append(const_cast<System::String*>(Constants::usChar)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sByte))) + buf->Append(const_cast<System::String*>(Constants::usByte)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt16))) + buf->Append(const_cast<System::String*>(Constants::usShort)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt16))) + buf->Append(const_cast<System::String*>(Constants::usUShort)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt32))) + buf->Append(const_cast<System::String*>(Constants::usLong)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt32))) + buf->Append(const_cast<System::String*>(Constants::usULong)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sInt64))) + buf->Append(const_cast<System::String*>(Constants::usHyper)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sUInt64))) + buf->Append(const_cast<System::String*>(Constants::usUHyper)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sSingle))) + buf->Append(const_cast<System::String*>(Constants::usFloat)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sDouble))) + buf->Append(const_cast<System::String*>(Constants::usDouble)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sString))) + buf->Append(const_cast<System::String*>(Constants::usString)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sVoid))) + buf->Append(const_cast<System::String*>(Constants::usVoid)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sType))) + buf->Append(const_cast<System::String*>(Constants::usType)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sObject))) + buf->Append(const_cast<System::String*>(Constants::usXInterface)); + else if (typeName->Equals(const_cast<System::String*>(Constants::sAny))) + buf->Append(const_cast<System::String*>(Constants::usAny)); + else + { + System::String * sName = mapCliPolymorphicName(typeName); + int i= sName->IndexOf(L'.'); + buf->Append(sName->Substring(i + 1)); + } + return mapCliString(buf->ToString()); +} +/** Maps uno types to dot net types. + * If uno_data is null then the type description is converted to System::Type + */ +inline System::String* mapUnoString( rtl_uString const * data) +{ + OSL_ASSERT(data); + return new System::String((__wchar_t*) data->buffer, 0, data->length); +} + +OUString mapCliString(System::String const * data) +{ + + if (data != NULL) + { + OSL_ASSERT(sizeof(wchar_t) == sizeof(sal_Unicode)); + wchar_t const __pin * pdata= PtrToStringChars(data); + return OUString(pdata, const_cast<System::String*>(data)->get_Length()); + } + else + { + return OUString(); + } +} + +// ToDo convert cli types to expected types, e.g a long to a short where the uno type +// is a sal_Int16. This could be necessary if a scripting language (typeless) is used +// @param assign the uno_data has to be destructed (in/out args) +void Bridge::map_to_uno(void * uno_data, System::Object* cli_data, + typelib_TypeDescriptionReference * type, + bool assign) const +{ + try{ + switch (type->eTypeClass) + { + case typelib_TypeClass_VOID: + break; + case typelib_TypeClass_CHAR: + { + System::Char aChar= *__try_cast<System::Char*>(cli_data); + *(sal_Unicode*) uno_data= aChar; + break; + } + case typelib_TypeClass_BOOLEAN: + { + System::Boolean aBool= *__try_cast<System::Boolean*>(cli_data); + *(sal_Bool*)uno_data= aBool == true ? sal_True : sal_False; + break; + } + case typelib_TypeClass_BYTE: + { + System::Byte aByte= *__try_cast<System::Byte*>(cli_data); + *(sal_Int8*) uno_data= aByte; + break; + } + case typelib_TypeClass_SHORT: + { + System::Int16 aShort= *__try_cast<System::Int16*>(cli_data); + *(sal_Int16*) uno_data= aShort; + break; + } + case typelib_TypeClass_UNSIGNED_SHORT: + { + System::UInt16 aUShort= *__try_cast<System::UInt16*>(cli_data); + *(sal_uInt16*) uno_data= aUShort; + break; + } + case typelib_TypeClass_LONG: + { + System::Int32 aLong= *__try_cast<System::Int32*>(cli_data); + *(sal_Int32*) uno_data= aLong; + break; + } + case typelib_TypeClass_UNSIGNED_LONG: + { + System::UInt32 aULong= *__try_cast<System::UInt32*>(cli_data); + *(sal_uInt32*) uno_data= aULong; + break; + } + case typelib_TypeClass_HYPER: + { + System::Int64 aHyper= *__try_cast<System::Int64*>(cli_data); + *(sal_Int64*) uno_data= aHyper; + break; + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + System::UInt64 aLong= *__try_cast<System::UInt64*>(cli_data); + *(sal_uInt64*) uno_data= aLong; + break; + } + case typelib_TypeClass_FLOAT: + { + System::Single aFloat= *__try_cast<System::Single*>(cli_data); + *(float*) uno_data= aFloat; + break; + } + case typelib_TypeClass_DOUBLE: + { + System::Double aDouble= *__try_cast<System::Double*>(cli_data); + *(double*) uno_data= aDouble; + break; + } + case typelib_TypeClass_STRING: + { + if (assign && *(rtl_uString**) uno_data) + rtl_uString_release(*(rtl_uString**) uno_data); + + *(rtl_uString **)uno_data = 0; + if (cli_data == NULL) + { + rtl_uString_new((rtl_uString**) uno_data); + } + else + { + System::String *s= __try_cast<System::String*>(cli_data); + wchar_t const __pin * pdata= PtrToStringChars(s); + rtl_uString_newFromStr_WithLength( (rtl_uString**) uno_data, + pdata, s->get_Length() ); + } + break; + } + case typelib_TypeClass_TYPE: + { + typelib_TypeDescriptionReference* td= mapCliType(__try_cast<System::Type*>( + cli_data)); + if (assign) + { + typelib_typedescriptionreference_release( + *(typelib_TypeDescriptionReference **)uno_data ); + } + *(typelib_TypeDescriptionReference **)uno_data = td; + break; + } + case typelib_TypeClass_ANY: + { + uno_Any * pAny = (uno_Any *)uno_data; + if (cli_data == NULL) // null-ref or uninitialized any maps to empty any + { + if (assign) + uno_any_destruct( pAny, 0 ); + uno_any_construct( pAny, 0, 0, 0 ); + break; + } + uno::Any aAny= *__try_cast<uno::Any*>(cli_data); + css::uno::Type value_td( mapCliType(aAny.Type), SAL_NO_ACQUIRE); + + if (assign) + uno_any_destruct( pAny, 0 ); + + try + { + switch (value_td.getTypeClass()) + { + case typelib_TypeClass_VOID: + pAny->pData = &pAny->pReserved; + break; + case typelib_TypeClass_CHAR: + pAny->pData = &pAny->pReserved; + *(sal_Unicode*) &pAny->pReserved = *__try_cast<System::Char*>(aAny.Value); + break; + case typelib_TypeClass_BOOLEAN: + pAny->pData = &pAny->pReserved; + *(sal_Bool *) &pAny->pReserved = *__try_cast<System::Boolean*>(aAny.Value); + break; + case typelib_TypeClass_BYTE: + pAny->pData = &pAny->pReserved; + *(sal_Int8*) &pAny->pReserved = *__try_cast<System::Byte*>(aAny.Value); + break; + case typelib_TypeClass_SHORT: + pAny->pData = &pAny->pReserved; + *(sal_Int16*) &pAny->pReserved = *__try_cast<System::Int16*>(aAny.Value); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + pAny->pData = &pAny->pReserved; + *(sal_uInt16*) &pAny->pReserved = *__try_cast<System::UInt16*>(aAny.Value); + break; + case typelib_TypeClass_LONG: + pAny->pData = &pAny->pReserved; + *(sal_Int32*) &pAny->pReserved = *__try_cast<System::Int32*>(aAny.Value); + break; + case typelib_TypeClass_UNSIGNED_LONG: + pAny->pData = &pAny->pReserved; + *(sal_uInt32*) &pAny->pReserved = *__try_cast<System::UInt32*>(aAny.Value); + break; + case typelib_TypeClass_HYPER: + if (sizeof (sal_Int64) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(sal_Int64*) &pAny->pReserved = *__try_cast<System::Int64*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_Int64) ) ); + *(sal_Int64 *) mem.get()= *__try_cast<System::Int64*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof (sal_uInt64) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(sal_uInt64*) &pAny->pReserved = *__try_cast<System::UInt64*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_uInt64) ) ); + *(sal_uInt64 *) mem.get()= *__try_cast<System::UInt64*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_FLOAT: + if (sizeof (float) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(float*) &pAny->pReserved = *__try_cast<System::Single*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (float) ) ); + *(float*) mem.get() = *__try_cast<System::Single*>(aAny.Value); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_DOUBLE: + if (sizeof (double) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(double*) &pAny->pReserved= *__try_cast<System::Double*>(aAny.Value); + } + else + { + auto_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (double) ) ); + *(double*) mem.get()= *__try_cast<System::Double*>(aAny.Value); + pAny->pData= mem.release(); + } + break; + case typelib_TypeClass_STRING: // anies often contain strings; copy string directly + { + pAny->pData= &pAny->pReserved; + OUString _s = mapCliString(static_cast<System::String*>(aAny.Value)); + pAny->pReserved= _s.pData; + rtl_uString_acquire(_s.pData); + break; + } + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ENUM: //ToDo copy enum direct + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + pAny->pData = &pAny->pReserved; + pAny->pReserved = 0; + map_to_uno( + &pAny->pReserved, aAny.Value, value_td.getTypeLibType(), + false /* no assign */); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + css::uno::Type anyType(value_td); + typelib_TypeDescription* td= NULL; + anyType.getDescription(&td); + auto_ptr< rtl_mem > mem(rtl_mem::allocate(td->nSize)); + typelib_typedescription_release(td); + map_to_uno( + mem.get(), aAny.Value, value_td.getTypeLibType(), + false /* no assign */); + pAny->pData = mem.release(); + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported value type of any!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + catch(System::InvalidCastException* ) + { +// ToDo check this + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + OUStringBuffer buf( 256 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():Any") ); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("]The Any type ")); + buf.append(value_td.getTypeName()); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" does not correspont " + "to its value type: ") ); + if(aAny.Value != NULL) + { + css::uno::Type td(mapCliType(aAny.Value->GetType()), SAL_NO_ACQUIRE); + buf.append(td.getTypeName()); + } + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError& ) + { + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw; + } + catch (...) + { + if (assign) + uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any + throw; + } + + pAny->pType = value_td.getTypeLibType(); + typelib_typedescriptionreference_acquire(pAny->pType); + break; + } + case typelib_TypeClass_ENUM: + { + // InvalidCastException is caught at the end of this method + System::Int32 aEnum= System::Convert::ToInt32((cli_data)); + *(sal_Int32*) uno_data = aEnum; + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + css::uno::TypeDescription td(type); + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription*) td.get(); + + typelib_StructTypeDescription * struct_td = NULL; + if (type->eTypeClass == typelib_TypeClass_STRUCT) + struct_td = (typelib_StructTypeDescription*) td.get(); + + if ( ! ((typelib_TypeDescription*) comp_td)->bComplete) + ::typelib_typedescription_complete( + (typelib_TypeDescription**) & comp_td ); + + sal_Int32 nMembers = comp_td->nMembers; + boolean bException= false; + System::Type* cliType = NULL; + if (cli_data) + cliType = cli_data->GetType(); + + if (0 != comp_td->pBaseTypeDescription) + { + map_to_uno( + uno_data, cli_data, + ((typelib_TypeDescription *)comp_td->pBaseTypeDescription)->pWeakRef, + assign); + } + sal_Int32 nPos = 0; + try + { + typelib_TypeDescriptionReference * member_type= NULL; + + rtl::OUString usUnoException(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception")); + for (; nPos < nMembers; ++nPos) + { + member_type= comp_td->ppTypeRefs[nPos]; +#if OSL_DEBUG_LEVEL >= 2 + System::String* __s; + sr::FieldInfo* arFields[]; + __s = mapUnoString(comp_td->ppMemberNames[nPos]); + arFields = cliType != NULL ? cliType->GetFields() : NULL; +#endif + System::Object* val= NULL; + if (cli_data != NULL) + { + sr::FieldInfo* aField= cliType->GetField( + mapUnoString(comp_td->ppMemberNames[nPos])); + // special case for Exception.Message property + // The com.sun.star.uno.Exception.Message field is mapped to the + // System.Exception property. Type.GetField("Message") returns null + if ( ! aField && usUnoException.equals(td.get()->pTypeName)) + {// get Exception.Message property + rtl::OUString usMessageMember(RTL_CONSTASCII_USTRINGPARAM("Message")); + if (usMessageMember.equals(comp_td->ppMemberNames[nPos])) + { + sr::PropertyInfo* pi= cliType->GetProperty( + mapUnoString(comp_td->ppMemberNames[nPos])); + val= pi->GetValue(cli_data, NULL); + } + else + { + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("[map_to_uno(): Member: ")); + buf.append(comp_td->ppMemberNames[nPos]); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + } + else + { + val= aField->GetValue(cli_data); + } + } + void * p = (char *) uno_data + comp_td->pMemberOffsets[ nPos ]; + //When using polymorphic structs then the parameterized members can be null. + //Then we set a default value. + bool bDefault = ((struct_td != NULL + && struct_td->pParameterizedTypes != NULL + && struct_td->pParameterizedTypes[nPos] == sal_True + && val == NULL) + || cli_data == NULL) ? true : false; + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (bDefault) + *(sal_Unicode*) p = 0; + else + *(sal_Unicode*) p = *__try_cast<System::Char*>(val); + break; + case typelib_TypeClass_BOOLEAN: + if (bDefault) + *(sal_Bool*) p = sal_False; + else + *(sal_Bool*) p = *__try_cast<System::Boolean*>(val); + break; + case typelib_TypeClass_BYTE: + if (bDefault) + *(sal_Int8*) p = 0; + else + *(sal_Int8*) p = *__try_cast<System::Byte*>(val); + break; + case typelib_TypeClass_SHORT: + if (bDefault) + *(sal_Int16*) p = 0; + else + *(sal_Int16*) p = *__try_cast<System::Int16*>(val); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + if (bDefault) + *(sal_uInt16*) p = 0; + else + *(sal_uInt16*) p = *__try_cast<System::UInt16*>(val); + break; + case typelib_TypeClass_LONG: + if (bDefault) + *(sal_Int32*) p = 0; + else + *(sal_Int32*) p = *__try_cast<System::Int32*>(val); + break; + case typelib_TypeClass_UNSIGNED_LONG: + if (bDefault) + *(sal_uInt32*) p = 0; + else + *(sal_uInt32*) p = *__try_cast<System::UInt32*>(val); + break; + case typelib_TypeClass_HYPER: + if (bDefault) + *(sal_Int64*) p = 0; + else + *(sal_Int64*) p = *__try_cast<System::Int64*>(val); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + if (bDefault) + *(sal_uInt64*) p = 0; + else + *(sal_uInt64*) p= *__try_cast<System::UInt64*>(val); + break; + case typelib_TypeClass_FLOAT: + if (bDefault) + *(float*) p = 0.; + else + *(float*) p = *__try_cast<System::Single*>(val); + break; + case typelib_TypeClass_DOUBLE: + if (bDefault) + *(double*) p = 0.; + else + *(double*) p = *__try_cast<System::Double*>(val); + break; + default: + { // ToDo enum, should be converted here + map_to_uno(p, val, member_type, assign); + break; + } + } + } + } + catch (BridgeRuntimeError& e) + { + bException= true; + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("[map_to_uno():")); + if (cliType) + { + buf.append(mapCliString(cliType->get_FullName())); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(".")); + buf.append(comp_td->ppMemberNames[nPos]); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" ")); + } + buf.append(e.m_message); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (System::InvalidCastException* ) + { + bException= true; + OUStringBuffer buf( 256 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + if (cliType) + { + buf.append(mapCliString(cliType->get_FullName())); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(".")); + buf.append(comp_td->ppMemberNames[nPos]); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] Value has not the required type.")); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (...) + { + OSL_ASSERT(0); + bException= true; + throw; + } + __finally + { + if (bException && !assign) // if assign then caller cleans up + { + // cleanup the members which we have converted so far + for ( sal_Int32 nCleanup = 0; nCleanup < nPos; ++nCleanup ) + { + uno_type_destructData( + uno_data, comp_td->ppTypeRefs[ nCleanup ], 0 ); + } + if (0 != comp_td->pBaseTypeDescription) + { + uno_destructData( + uno_data, (typelib_TypeDescription *)comp_td->pBaseTypeDescription, 0 ); + } + } + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + auto_ptr< rtl_mem > seq; + + System::Array* ar = NULL; + if (cli_data != NULL) + { + ar = __try_cast<System::Array*>(cli_data); + sal_Int32 nElements = ar->GetLength(0); + + try + { + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + seq = seq_allocate(nElements, sizeof (sal_Unicode)); + sri::Marshal::Copy(__try_cast<System::Char[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_BOOLEAN: + seq = seq_allocate(nElements, sizeof (sal_Bool)); + sri::Marshal::Copy(__try_cast<System::Boolean[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_BYTE: + seq = seq_allocate( nElements, sizeof (sal_Int8) ); + sri::Marshal::Copy(__try_cast<System::Byte[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_SHORT: + seq = seq_allocate(nElements, sizeof (sal_Int16)); + sri::Marshal::Copy(__try_cast<System::Int16[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + seq = seq_allocate( nElements, sizeof (sal_uInt16) ); + sri::Marshal::Copy(static_cast<System::Int16[]>( + __try_cast<System::UInt16[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_LONG: + seq = seq_allocate(nElements, sizeof (sal_Int32)); + sri::Marshal::Copy(__try_cast<System::Int32[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_LONG: + seq = seq_allocate( nElements, sizeof (sal_uInt32) ); + sri::Marshal::Copy(static_cast<System::Int32[]>( + __try_cast<System::UInt32[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_HYPER: + seq = seq_allocate(nElements, sizeof (sal_Int64)); + sri::Marshal::Copy(__try_cast<System::Int64[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + seq = seq_allocate(nElements, sizeof (sal_uInt64)); + sri::Marshal::Copy(static_cast<System::Int64[]>( + __try_cast<System::UInt64[]>(cli_data)), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_FLOAT: + seq = seq_allocate(nElements, sizeof (float)); + sri::Marshal::Copy(__try_cast<System::Single[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_DOUBLE: + seq = seq_allocate(nElements, sizeof (double)); + sri::Marshal::Copy(__try_cast<System::Double[]>(cli_data), 0, + & ((uno_Sequence*) seq.get())->elements, nElements); + break; + case typelib_TypeClass_STRING: + { + seq = seq_allocate(nElements, sizeof (rtl_uString*)); + System::String* arStr[]= __try_cast<System::String*[]>(cli_data); + for (int i= 0; i < nElements; i++) + { + wchar_t const __pin * pdata= PtrToStringChars(arStr[i]); + rtl_uString** pStr= & ((rtl_uString**) & + ((uno_Sequence*) seq.get())->elements)[i]; + *pStr= NULL; + rtl_uString_newFromStr_WithLength( pStr, pdata, + arStr[i]->get_Length()); + } + break; + } + case typelib_TypeClass_ENUM: + seq = seq_allocate(nElements, sizeof (sal_Int32)); + for (int i= 0; i < nElements; i++) + { + ((sal_Int32*) &((uno_Sequence*) seq.get())->elements)[i]= + System::Convert::ToInt32(ar->GetValue(i)); + } + break; + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + { + TypeDescr element_td( element_type ); + seq = seq_allocate( nElements, element_td.get()->nSize ); + + for (sal_Int32 nPos = 0; nPos < nElements; ++nPos) + { + try + { + void * p= ((uno_Sequence *) seq.get())->elements + + (nPos * element_td.get()->nSize); + System::Object* elemData= dynamic_cast<System::Array*>(cli_data)->GetValue(nPos); + map_to_uno( + p, elemData, element_td.get()->pWeakRef, + false /* no assign */); + } + catch (...) + { + // cleanup + for ( sal_Int32 nCleanPos = 0; nCleanPos < nPos; ++nCleanPos ) + { + void * p = + ((uno_Sequence *)seq.get())->elements + + (nCleanPos * element_td.get()->nSize); + uno_destructData( p, element_td.get(), 0 ); + } + throw; + } + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported sequence element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + catch (BridgeRuntimeError& e) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName )); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] conversion failed\n ")); + buf.append(e.m_message); + throw BridgeRuntimeError(buf.makeStringAndClear()); + } + catch (System::InvalidCastException* ) + { + // Ok, checked + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] could not convert sequence element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (...) + { + OSL_ASSERT(0); + throw; + } + __finally + { + if (assign) + uno_destructData( uno_data, td.get(), 0 ); + } + } + else + { + seq = seq_allocate(0, sizeof (sal_Int32)); + } + *(uno_Sequence **)uno_data = (uno_Sequence *)seq.release(); + break; + } + case typelib_TypeClass_INTERFACE: + { + if (assign) + { + uno_Interface * p = *(uno_Interface **)uno_data; + if (0 != p) + (*p->release)( p ); + } + if (0 == cli_data) // null-ref + { + *(uno_Interface **)uno_data = 0; + } + else + { + TypeDescr td( type ); + uno_Interface * pUnoI = map_cli2uno(cli_data, td.get()); + *(uno_Interface **)uno_data = pUnoI; + } + break; + } + default: + { + //ToDo check + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + // BridgeRuntimeError are allowed to be thrown + catch (System::InvalidCastException* ) + { + //ToDo check + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] could not convert type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (System::NullReferenceException * e) + { + OUStringBuffer buf(512); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( + "[map_to_uno()] Illegal null reference passed!\n")); + buf.append(mapCliString(e->get_StackTrace())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError& ) + { + throw; + } + catch (...) + { + OSL_ASSERT(0); + throw; + } + +} + +/** + @param info + The expected target type. Currently info is provdided when this method is called + to convert the in/out and out parameters of a call from cli to uno. Then info + is always a byref type, e.g. "System.String&". info is used for Any and Enum conversion. + @param bDontCreateObj + false - a new object is created which holds the mapped uno value and is assigned to + cli_data. + true - cli_data already contains the newly constructed object. This is the case if + a struct is converted then on the first call to map_to_cli the new object is created. + If the struct inherits another struct then this function is called recursivly while the + newly created object is passed in cli_data. + */ +void Bridge::map_to_cli( + System::Object* *cli_data, void const * uno_data, + typelib_TypeDescriptionReference * type, System::Type* info, + bool bDontCreateObj) const +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_CHAR: + *cli_data= __box(*(__wchar_t const*)uno_data); + break; + case typelib_TypeClass_BOOLEAN: + *cli_data = __box((*(bool const*)uno_data) == sal_True ? true : false); + break; + case typelib_TypeClass_BYTE: + *cli_data = __box(*(unsigned char const*) uno_data); + break; + case typelib_TypeClass_SHORT: + *cli_data= __box(*(short const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + *cli_data= __box(*(unsigned short const*) uno_data); + break; + case typelib_TypeClass_LONG: + *cli_data= __box(*(int const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_LONG: + *cli_data= __box(*(unsigned int const*) uno_data); + break; + case typelib_TypeClass_HYPER: + *cli_data= __box(*(__int64 const*) uno_data); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + *cli_data= __box(*(unsigned __int64 const*) uno_data); + break; + case typelib_TypeClass_FLOAT: + *cli_data= __box(*(float const*) uno_data); + break; + case typelib_TypeClass_DOUBLE: + *cli_data= __box(*(double const*) uno_data); + break; + case typelib_TypeClass_STRING: + { + rtl_uString const* sVal= NULL; + sVal= *(rtl_uString* const*) uno_data; + *cli_data= new System::String((__wchar_t*) sVal->buffer,0, sVal->length); + break; + } + case typelib_TypeClass_TYPE: + { + *cli_data= mapUnoType( *(typelib_TypeDescriptionReference * const *)uno_data ); + break; + } + case typelib_TypeClass_ANY: + { + uno_Any const * pAny = (uno_Any const *)uno_data; + if (typelib_TypeClass_VOID != pAny->pType->eTypeClass) + { + System::Object* objCli= NULL; + map_to_cli( + &objCli, pAny->pData, pAny->pType, 0, + false); + + uno::Any anyVal(mapUnoType(pAny->pType), objCli); + *cli_data= __box(anyVal); + } + else + { // void any + *cli_data= __box(uno::Any::VOID); + } + break; + } + case typelib_TypeClass_ENUM: + { + if (info != NULL) + { + OSL_ASSERT(info->get_IsByRef()); + info= info->GetElementType(); + *cli_data= System::Enum::ToObject(info, *(System::Int32*) uno_data); + } + else + *cli_data= System::Enum::ToObject( + mapUnoType(type), *(System::Int32*) uno_data); + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + TypeDescr td( type ); + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription *) td.get(); + if ( ! ((typelib_TypeDescription*) comp_td)->bComplete) + ::typelib_typedescription_complete( + (typelib_TypeDescription**) & comp_td ); + + + //create the type + System::Type* cliType= loadCliType(td.get()->pTypeName); + //detect if we recursivly convert inherited structures + //If this point is reached because of a recursive call during convering a + //struct then we must not create a new object rather we use the one in + // cli_data argument. + System::Object* cliObj; + if (bDontCreateObj) + cliObj = *cli_data; // recursive call + else + { + //Special handling for Exception conversion. We must call constructor System::Exception + //to pass the message string + if (__typeof(ucss::uno::Exception)->IsAssignableFrom(cliType)) + { + //We need to get the Message field. Therefore we must obtain the offset from + //the typedescription. The base interface of all exceptions is + //com::sun::star::uno::Exception which contains the message + typelib_CompoundTypeDescription* pCTD = comp_td; + while (pCTD->pBaseTypeDescription) + pCTD = pCTD->pBaseTypeDescription; + int nPos = -1; + + rtl::OUString usMessageMember(RTL_CONSTASCII_USTRINGPARAM("Message")); + for (int i = 0; i < pCTD->nMembers; i ++) + { +#if OSL_DEBUG_LEVEL >= 2 + System::String* sMember; + sMember = mapUnoString(pCTD->ppMemberNames[i]); +#endif + if (usMessageMember.equals(pCTD->ppMemberNames[i])) + { + nPos = i; + break; + } + } + OSL_ASSERT (nPos != -1); + int offset = pCTD->pMemberOffsets[nPos]; + //Whith the offset within the exception we can get the message string + System::String* sMessage = mapUnoString(*(rtl_uString**) + ((char*) uno_data + offset)); + //We need to find a constructor for the exception that takes the message string + //We assume that the first argument is the message string + sr::ConstructorInfo* arCtorInfo[] = cliType->GetConstructors(); + sr::ConstructorInfo* ctorInfo = NULL; + int numCtors = arCtorInfo->get_Length(); + //Constructor must at least have 2 params for the base + //unoidl.com.sun.star.uno.Exception (String, Object); + sr::ParameterInfo * arParamInfo[]; + for (int i = 0; i < numCtors; i++) + { + arParamInfo = arCtorInfo[i]->GetParameters(); + if (arParamInfo->get_Length() < 2) + continue; + ctorInfo = arCtorInfo[i]; + break; + } + OSL_ASSERT(arParamInfo[0]->get_ParameterType()->Equals(__typeof(System::String)) + && arParamInfo[1]->get_ParameterType()->Equals(__typeof(System::Object)) + && arParamInfo[0]->get_Position() == 0 + && arParamInfo[1]->get_Position() == 1); + //Prepare parameters for constructor + int numArgs = arParamInfo->get_Length(); + System::Object * args[] = new System::Object*[numArgs]; + //only initialize the first argument with the message + args[0] = sMessage; + cliObj = ctorInfo->Invoke(args); + } + else + cliObj = System::Activator::CreateInstance(cliType); + } + sal_Int32 * pMemberOffsets = comp_td->pMemberOffsets; + + if (comp_td->pBaseTypeDescription) + { + //convert inherited struct + //cliObj is passed inout (args in_param, out_param are true), hence the passed + // cliObj is used by the callee instead of a newly created struct + map_to_cli( + &cliObj, uno_data, + ((typelib_TypeDescription *)comp_td->pBaseTypeDescription)->pWeakRef, 0, + true); + } + rtl::OUString usUnoException(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception")); + for (sal_Int32 nPos = comp_td->nMembers; nPos--; ) + { + typelib_TypeDescriptionReference * member_type = comp_td->ppTypeRefs[ nPos ]; + System::String* sMemberName= mapUnoString(comp_td->ppMemberNames[nPos]); + sr::FieldInfo* aField= cliType->GetField(sMemberName); + // special case for Exception.Message. The field has already been + // set while constructing cli object + if ( ! aField && usUnoException.equals(td.get()->pTypeName)) + { + continue; + } + void const * p = (char const *)uno_data + pMemberOffsets[ nPos ]; + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + aField->SetValue(cliObj, __box(*(System::Char*) p)); + break; + case typelib_TypeClass_BOOLEAN: + aField->SetValue(cliObj, __box(*(System::Boolean*) p)); + break; + case typelib_TypeClass_BYTE: + aField->SetValue(cliObj, __box(*(System::Byte*) p)); + break; + case typelib_TypeClass_SHORT: + aField->SetValue(cliObj, __box(*(System::Int16*) p)); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + aField->SetValue(cliObj, __box(*(System::UInt16*) p)); + break; + case typelib_TypeClass_LONG: + aField->SetValue(cliObj, __box(*(System::Int32*) p)); + break; + case typelib_TypeClass_UNSIGNED_LONG: + aField->SetValue(cliObj, __box(*(System::UInt32*) p)); + break; + case typelib_TypeClass_HYPER: + aField->SetValue(cliObj, __box(*(System::Int64*) p)); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + aField->SetValue(cliObj, __box(*(System::UInt64*) p)); + break; + case typelib_TypeClass_FLOAT: + aField->SetValue(cliObj, __box(*(System::Single*) p)); + break; + case typelib_TypeClass_DOUBLE: + aField->SetValue(cliObj, __box(*(System::Double*) p)); + break; + default: + { + System::Object* cli_val; + map_to_cli( + &cli_val, p, member_type, 0, + false); + aField->SetValue(cliObj, cli_val); + break; + } + } + } + *cli_data= cliObj; + break; + } + case typelib_TypeClass_SEQUENCE: + { + sal_Int32 nElements; + uno_Sequence const * seq = 0; + seq = *(uno_Sequence * const *)uno_data; + nElements = seq->nElements; + + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + { + System::Char arChar[]= new System::Char[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arChar, 0, nElements); + *cli_data= arChar; + break; + } + case typelib_TypeClass_BOOLEAN: + { + System::Boolean arBool[]= new System::Boolean[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arBool, 0, nElements); + *cli_data= arBool; + break; + } + case typelib_TypeClass_BYTE: + { + System::Byte arByte[]= new System::Byte[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arByte, 0, nElements); + *cli_data= arByte; + break; + } + case typelib_TypeClass_SHORT: + { + System::Int16 arShort[]= new System::Int16[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arShort, 0, nElements); + *cli_data= arShort; + break; + } + case typelib_TypeClass_UNSIGNED_SHORT: + { + System::UInt16 arUInt16[]= new System::UInt16[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, static_cast<System::Int16[]>(arUInt16), + 0, nElements); + *cli_data= arUInt16; + break; + } + case typelib_TypeClass_LONG: + { + System::Int32 arInt32[]= new System::Int32[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arInt32, 0, nElements); + *cli_data= arInt32; + break; + } + case typelib_TypeClass_UNSIGNED_LONG: + { + System::UInt32 arUInt32[]= new System::UInt32[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, static_cast<System::Int32[]>(arUInt32), + 0, nElements); + *cli_data= arUInt32; + break; + } + case typelib_TypeClass_HYPER: + { + System::Int64 arInt64[]= new System::Int64[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arInt64, 0, nElements); + *cli_data= arInt64; + break; + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + System::UInt64 arUInt64[]= new System::UInt64[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arUInt64, 0, nElements); + *cli_data= arUInt64; + break; + } + case typelib_TypeClass_FLOAT: + { + System::Single arSingle[]= new System::Single[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arSingle, 0, nElements); + *cli_data= arSingle; + break; + } + case typelib_TypeClass_DOUBLE: + { + System::Double arDouble[]= new System::Double[nElements]; + sri::Marshal::Copy( (void*) &seq->elements, arDouble, 0, nElements); + *cli_data= arDouble; + break; + } + case typelib_TypeClass_STRING: + { + System::String* arString[]= new System::String*[nElements]; + for (int i= 0; i < nElements; i++) + { + rtl_uString *aStr= ((rtl_uString**)(&seq->elements))[i]; + arString[i]= new System::String( (__wchar_t *) &aStr->buffer, 0, aStr->length); + } + *cli_data= arString; + break; + } + case typelib_TypeClass_TYPE: + { + System::Type* arType[]= new System::Type*[nElements]; + for (int i= 0; i < nElements; i++) + { + arType[i]= + mapUnoType( ((typelib_TypeDescriptionReference**) seq->elements)[i]); + } + *cli_data= arType; + break; + } + case typelib_TypeClass_ANY: + { + uno::Any arCli[]= new uno::Any[nElements]; + uno_Any const * p = (uno_Any const *)seq->elements; + for (sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* cli_obj = NULL; + map_to_cli( + &cli_obj, &p[ nPos ], element_type, 0, false); + arCli[nPos]= *__try_cast<__box uno::Any*>(cli_obj); + } + *cli_data= arCli; + break; + } + case typelib_TypeClass_ENUM: + { + //get the Enum type + System::Type* enumType= NULL; + if (info != NULL) + { + //info is EnumType[]&, remove & + OSL_ASSERT(info->IsByRef); + enumType = info->GetElementType(); + //enumType is EnumType[], remove [] + enumType = enumType->GetElementType(); + } + else + enumType= mapUnoType(element_type); + + System::Array* arEnum = System::Array::CreateInstance( + enumType, nElements); + for (int i= 0; i < nElements; i++) + { + arEnum->SetValue(System::Enum::ToObject(enumType, + ((sal_Int32*) seq->elements)[i]), i); + } + *cli_data = arEnum; + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + TypeDescr element_td( element_type ); + System::Array* ar= System::Array::CreateInstance( + mapUnoType(element_type),nElements); + if (0 < nElements) + { + // ToDo check this + char * p = (char *) &seq->elements; + sal_Int32 nSize = element_td.get()->nSize; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, p + (nSize * nPos), element_type, 0, false); + ar->SetValue(val, nPos); + } + } + *cli_data = ar; + break; + } +// ToDo, verify + case typelib_TypeClass_SEQUENCE: + { + System::Array *ar= System::Array::CreateInstance( + mapUnoType(element_type), nElements); + if (0 < nElements) + { + TypeDescr element_td( element_type ); + uno_Sequence ** elements = (uno_Sequence**) seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, &elements[nPos], element_type, 0, false); + ar->SetValue(val, nPos); + } + } + *cli_data = ar; + break; + } + case typelib_TypeClass_INTERFACE: + { + TypeDescr element_td( element_type ); + System::Type * ifaceType= mapUnoType(element_type); + System::Array* ar= System::Array::CreateInstance(ifaceType, nElements); + + char * p = (char *)seq->elements; + sal_Int32 nSize = element_td.get()->nSize; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + System::Object* val; + map_to_cli( + &val, p + (nSize * nPos), element_type, NULL, false); + + ar->SetValue(val, nPos); + } + *cli_data= ar; + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_cli():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported element type: ") ); + buf.append( *reinterpret_cast< OUString const * >( &element_type->pTypeName ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + break; + } + case typelib_TypeClass_INTERFACE: + { + uno_Interface * pUnoI = *(uno_Interface * const *)uno_data; + if (0 != pUnoI) + { + TypeDescr td( type ); + *cli_data= map_uno2cli( pUnoI, reinterpret_cast< + typelib_InterfaceTypeDescription*>(td.get())) ; + } + else + *cli_data= NULL; + break; + } + default: + { + //ToDo check this exception. The String is probably crippled + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_cli():") ); + buf.append( *reinterpret_cast< OUString const * >( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } +} +} diff --git a/cli_ure/source/uno_bridge/cli_environment.cxx b/cli_ure/source/uno_bridge/cli_environment.cxx new file mode 100644 index 000000000000..cfa0f8e57817 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_environment.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include "Cli_environment.h" + +#using <mscorlib.dll> +#using <cli_ure.dll> +#using <system.dll> +#include "osl/diagnose.h" +#include "cli_proxy.h" + +using namespace System::Runtime::Remoting; +using namespace System::Runtime::Remoting::Proxies; +using namespace System::Collections; +using namespace System::Text; +using namespace System::Diagnostics; +using namespace System::Threading; + +namespace cli_uno +{ + +inline System::String* Cli_environment::createKey(System::String* oid, System::Type* t) +{ + return System::String::Concat(oid, t->get_FullName()); +} + + +inline Cli_environment::Cli_environment() +{ +#if OSL_DEBUG_LEVEL >= 2 + _numRegisteredObjects = 0; +#endif +} + +Cli_environment::~Cli_environment() +{ + OSL_ENSURE(_numRegisteredObjects == 0, + "cli uno bridge: CLI environment contains unrevoked objects"); +} + + +System::Object* Cli_environment::registerInterface( + System::Object* obj, System::String* oid) +{ +#if OSL_DEBUG_LEVEL >= 1 + //obj must be a transparent proxy + OSL_ASSERT(RemotingServices::IsTransparentProxy(obj)); + _numRegisteredObjects ++; +#endif + OSL_ASSERT( ! m_objects->ContainsKey(oid)); + m_objects->Add(oid, new WeakReference(obj)); + return obj; +} +System::Object* Cli_environment::registerInterface ( + System::Object* obj, System::String* oid, System::Type* type) +{ +#if OSL_DEBUG_LEVEL >= 1 + //obj must be a real cli object + OSL_ASSERT( ! RemotingServices::IsTransparentProxy(obj)); + _numRegisteredObjects ++; +#endif + System::String* key = createKey(oid, type); + //see synchronization in map_uno2cli in cli_data.cxx + OSL_ASSERT( ! m_objects->ContainsKey(key)); + m_objects->Add(key, new WeakReference(obj)); + return obj; +} + +void Cli_environment::revokeInterface(System::String* oid, System::Type* type) +{ + System::String* key = type != NULL ? createKey(oid, type) : oid; +#if OSL_DEBUG_LEVEL >= 1 + _numRegisteredObjects --; +#endif +#if OSL_DEBUG_LEVEL >= 2 + int i = 1; + if (m_objects->ContainsKey(key) == false) + { + Trace::WriteLine("cli uno bridge: try to revoke unregistered interface"); + Trace::WriteLine(oid); + i = 0; + } + Trace::WriteLine(System::String::Format( + new System::String(S"cli uno bridge: {0} remaining registered interfaces"), + __box(m_objects->get_Count() - 1))); +#endif + m_objects->Remove(key); +} + +inline void Cli_environment::revokeInterface(System::String* oid) +{ + return revokeInterface(oid, NULL); +} + +System::Object* Cli_environment::getRegisteredInterface(System::String* oid, + System::Type* type) +{ + //try if it is a UNO interface + System::Object* ret = NULL; + ret = m_objects->get_Item(oid); + if (! ret) + { + //try if if it is a proxy for a cli object + oid = createKey(oid, type); + ret = m_objects->get_Item( oid ); + } + if (ret != 0) + { + System::WeakReference* weakIface = + static_cast< System::WeakReference * >( ret ); + ret = weakIface->Target; + } + if (ret == 0) + m_objects->Remove( oid ); + return ret; +} + +System::String* Cli_environment::getObjectIdentifier(System::Object* obj) +{ + System::String* oId= 0; + RealProxy* aProxy= RemotingServices::GetRealProxy(obj); + if (aProxy) + { + UnoInterfaceProxy* proxyImpl= dynamic_cast<UnoInterfaceProxy*>(aProxy); + if (proxyImpl) + oId= proxyImpl->getOid(); + } + + if (oId == 0) + { + StringBuilder * buf= new StringBuilder(256); + bool bFirst = false; + System::Threading::Monitor::Enter(__typeof(Cli_environment)); + try { + buf->Append(m_IDGen->GetId(obj, & bFirst)); + } __finally + { + System::Threading::Monitor::Exit(__typeof(Cli_environment)); + } + + buf->Append(sOidPart); + oId= buf->ToString(); + } + return oId; +} +} //namespace cli_uno diff --git a/cli_ure/source/uno_bridge/cli_environment.h b/cli_ure/source/uno_bridge/cli_environment.h new file mode 100644 index 000000000000..486d5c169807 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_environment.h @@ -0,0 +1,114 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_CLI_ENVIRONMENT_H +#define INCLUDED_CLI_ENVIRONMENT_H + +#include "cli_base.h" +#using <mscorlib.dll> + +using namespace System; +using namespace System::Collections; +using namespace System::Runtime::Serialization; + +namespace cli_uno +{ + +public __gc class Cli_environment +{ + static System::String* sOidPart; + static Hashtable* m_objects; + static System::Runtime::Serialization::ObjectIDGenerator* m_IDGen; + inline static System::String* createKey(System::String* oid, System::Type* t); + +#if OSL_DEBUG_LEVEL >= 1 + int _numRegisteredObjects; +#endif + +public: + + static Cli_environment() + { + m_objects = Hashtable::Synchronized(new Hashtable()); + m_IDGen = new System::Runtime::Serialization::ObjectIDGenerator(); + System::Text::StringBuilder* buffer = new System::Text::StringBuilder(256); + Guid gd = Guid::NewGuid(); + buffer->Append(S";cli[0];"); + buffer->Append(gd.ToString()); + sOidPart = buffer->ToString(); + } + + inline Cli_environment(); + + ~Cli_environment(); + + /** + Registers an UNO object as being mapped by this bridge. The resulting + cli object is represents all interfaces of the UNO object. Therefore the + object can be registered only with its OID; a type is not necessary. + */ + Object* registerInterface(Object* obj, System::String* oid); + /** + Registers a CLI object as being mapped by this bridge. The resulting + object represents exactly one UNO interface. + */ + Object* registerInterface(Object* obj, System::String* oid, System::Type* type); + + /** + By revoking an interface it is declared that the respective interface has + not been mapped. The proxy implementations call revoke interface in their + destructors. + */ + inline void revokeInterface(System::String* oid); + + void revokeInterface(System::String* oid, System::Type* type); + /** + * Retrieves an interface identified by its object id and type from this + * environment. + * + * @param oid object id of interface to be retrieved + * @param type the type description of the interface to be retrieved + * @see com.sun.star.uno.IEnvironment#getRegisteredInterface + */ + Object* getRegisteredInterface(System::String* oid, System::Type* type); + + /** + * Generates a worldwide unique object identifier (oid) for the given object. It is + * guaranteed, that subsequent calls to the method with the same object + * will give the same id. + * <p> + * @return the generated oid. + * @param object the object for which a Oid should be generated. + */ + static System::String* getObjectIdentifier(Object* obj); + +}; + +} //namespace cli_uno + + +#endif diff --git a/cli_ure/source/uno_bridge/cli_proxy.cxx b/cli_ure/source/uno_bridge/cli_proxy.cxx new file mode 100644 index 000000000000..0fd662a24fe9 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.cxx @@ -0,0 +1,1178 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 + } +} + + + + + diff --git a/cli_ure/source/uno_bridge/cli_proxy.h b/cli_ure/source/uno_bridge/cli_proxy.h new file mode 100644 index 000000000000..2441bebf1365 --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_proxy.h @@ -0,0 +1,299 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_CLI_PROXY_H +#define INCLUDED_CLI_PROXY_H + +#pragma warning(push, 1) +#include "uno/environment.hxx" +#pragma warning(pop) +#include "uno/mapping.hxx" +#include "uno/dispatcher.h" +#include "cli_bridge.h" +#include "cli_environment.h" + +#using <mscorlib.dll> +#using <cli_ure.dll> + +namespace srrp = System::Runtime::Remoting::Proxies; +namespace srrm = System::Runtime::Remoting::Messaging; +namespace srr = System::Runtime::Remoting; +namespace sr = System::Reflection; +namespace sc = System::Collections; +using namespace uno; + +namespace cli_uno +{ + +public __gc class UnoInterfaceInfo +{ +public: + UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI, + typelib_InterfaceTypeDescription* td); + ~UnoInterfaceInfo(); + uno_Interface * m_unoI; // wrapped interface + System::Type * m_type; + typelib_InterfaceTypeDescription* m_typeDesc; + + Bridge const* m_bridge; +}; + +public __gc class UnoInterfaceProxy: public srrp::RealProxy, + public srr::IRemotingTypeInfo +{ + /** used for IRemotingTypeInfo.TypeName + */ + System::String* m_sTypeName; + /** The list is filled with UnoInterfaceInfo objects. The list can only + grow and elements are never changed. If an element was added it + must not be changed! + */ + sc::ArrayList* m_listIfaces; + /** The number of UNO interfaces this proxy represents. It corresponds + to the the number of elements in m_listIfaces. + */ + int m_numUnoIfaces; + /** The list is filled with additional UnoInterfaceProxy object due + to aggregation via bridges. Though the latter is strongly + discouraged, this has to be supported. + */ + sc::ArrayList* m_listAdditionalProxies; + int m_nlistAdditionalProxies; + + UnoInterfaceInfo * findInfo( ::System::Type * type ); + + Bridge const* m_bridge; + System::String* m_oid; + +#if OSL_DEBUG_LEVEL >= 2 + /** The string contains all names of UNO interfaces which are + represented by this proxy. It is used to print out the interfaces + when this proxy dies. In the destructor it is not allowed to + access m_listIfaces or any other managed object. + */ + rtl_uString * _sInterfaces; +// /** Count of interfaces. Used in conjunction with _sInterfaces. +// */ + int _numInterfaces; +#endif + +public: + + /** Creates a proxy and registers it on the dot NET side. + */ + static System::Object* create(Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTd, + const rtl::OUString& oid); + + /** RealProxy::Invoke */ + srrm::IMessage* Invoke(srrm::IMessage* msg); + + /** Must be called from within a synchronized section. + Add only the interface if it is not already contained. + This method is called from the constructor and as a result + of IRemotingTypeInfo::CanCastTo + */ + void addUnoInterface(uno_Interface* pUnoI, + typelib_InterfaceTypeDescription* pTd); + ~UnoInterfaceProxy(); + + /** + */ + inline System::String * getOid() + { return m_oid; } + + //IRemotingTypeInfo ---------------------------------------------- + bool CanCastTo(System::Type* fromType, System::Object* o); + + __property System::String* get_TypeName() + { + return m_sTypeName; + } + __property void set_TypeName(System::String* name) + { + m_sTypeName = name; + } + + +private: + UnoInterfaceProxy( + Bridge * bridge, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription* pTD, + const rtl::OUString& oid ); + + static srrm::IMessage* constructReturnMessage(System::Object* retVal, + System::Object* outArgs[], + typelib_InterfaceMethodTypeDescription* mtd, + srrm::IMessage* msg, System::Object* exc); + + static System::String* m_methodNameString = + new System::String("__MethodName"); + static System::String* m_typeNameString = new System::String("__TypeName"); + static System::String* m_ArgsString = new System::String("__Args"); + static System::String* m_CallContextString = + new System::String("__CallContext"); + static System::String* m_system_Object_String = + new System::String("System.Object"); + static System::String* m_methodSignatureString = + new System::String("__MethodSignature"); + static System::String* m_Equals_String = new System::String("Equals"); + static System::String* m_GetHashCode_String = + new System::String("GetHashCode"); + static System::String* m_GetType_String = new System::String("GetType"); + static System::String* m_ToString_String = new System::String("ToString"); + +protected: + srrm::IMessage* invokeObject(sc::IDictionary* properties, + srrm::LogicalCallContext* context, + srrm::IMethodCallMessage* mcm); +}; + + +//Cannot make this __gc because a managed type cannot derive from unmanaged type +struct CliProxy: public uno_Interface +{ + mutable oslInterlockedCount m_ref; + const Bridge* m_bridge; + const gcroot<System::Object*> m_cliI; + gcroot<System::Type*> m_type; + const com::sun::star::uno::TypeDescription m_unoType; + const gcroot<System::String*> m_oid; + const rtl::OUString m_usOid; + + enum MethodKind {MK_METHOD = 0, MK_SET, MK_GET}; + /** The array contains MethodInfos of the cli object. Each one reflects an + implemented interface method of the interface for which this proxy was + created. The MethodInfos are from the object's method and not from the + interface type. That is, they can be used to invoke the methods. The + order of the MethodInfo objects corresponds to the order of the + interface methods (see member m_type). Position 0 contains the + MethodInfo of the first method of the interface which represents the + root of the inheritance chain. The last MethodInfo represents the last + method of the furthest derived interface. + + The array is completely initialized in the constructor of this object. + + When the uno_DispatchMethod is called for this proxy then it receives + a typelib_TypeDescription of the member which is either an attribute + (setter or getter) or method. After determining the position of the + method within the UNO interface one can use the position to obtain the + MethodInfo of the corresponding cli method. To obtain the index for the + m_arMethodInfos array the function position has to be decreased by 3. + This is becaus, the cli interface does not contain the XInterface + methods. + */ + gcroot<sr::MethodInfo*[]> m_arMethodInfos; + + /** This array is similar to m_arMethodInfos but it contains the MethodInfo + objects of the interface (not the object). When a call is made from uno + to cli then the uno method name is compared to the cli method name. The + cli method name can be obtained from the MethodInfo object in this + array. The name of the actual implemented method may not be the same as + the interface method. + */ + gcroot<sr::MethodInfo*[]> m_arInterfaceMethodInfos; + + /** Maps the position of the method in the UNO interface to the position of + the corresponding MethodInfo in m_arMethodInfos. The Uno position must + not include the XInterface methods. For example, + pos 0 = XInterface::queryInterface + pos 1 = XInterface::acquire + pos 2 = XInterface::release + + That is the real Uno position has to be deducted by 3. Then + arUnoPosToCliPos[pos] contains the index for m_arMethodInfos. + + */ + gcroot<System::Int32[]> m_arUnoPosToCliPos; + + /** Count of inherited interfaces of the cli interface. + */ + int m_nInheritedInterfaces; + /** Contains the number of methods of each interface. + */ + gcroot<System::Int32[]> m_arInterfaceMethodCount; + + CliProxy( Bridge const* bridge, System::Object* cliI, + typelib_TypeDescription const* pTD, + const rtl::OUString& usOid); + ~CliProxy(); + + static uno_Interface* create(Bridge const * bridge, + System::Object* cliI, + typelib_TypeDescription const * TD, + rtl::OUString const & usOid ); + + /** Prepares an array (m_arMethoInfos) containing MethodInfo object of the + interface and all inherited interfaces. At index null is the first + method of the base interface and at the last position is the last method + of the furthest derived interface. + If a UNO call is received then one can determine the position of the + method (or getter or setter for an attribute) from the passed type + information. The position minus 3 (there is no XInterface in the cli + mapping) corresponds to the index of the cli interface method in the + array. + */ + void makeMethodInfos(); + + /**Obtains a MethodInfo which can be used to invoke the cli object. + Internally it maps nUnoFunctionPos to an index that is used to get the + corresponding MethodInfo object from m_arMethoInfos. The mapping table + is dynamically initialized. If the cli interface has no base interface + or exactly one then the mapping table is initialized in one go at the + first call. In all ensuing calls the MethodInfo object is immediately + retrieved through the mapping table. + + If the interface has more then one interface in its inheritance chain, + that is Type.GetInterfaces return more then one Type, then the mapping + table is partially initiallized. On the first call the mappings for the + methods of the belonging interface are created. + + The implementation assumes that the order of interface methods as + provided by InterfaceMapping.InterfaceMethods corresponds to the order + of methods in the interface declaration. + + @param nUnoFunctionPos + Position of the method in the uno interface. + */ + sr::MethodInfo* getMethodInfo(int nUnoFunctionPos, + const rtl::OUString & usMethodName, + MethodKind mk); + + void SAL_CALL uno_DispatchMethod( + struct _uno_Interface * pUnoI, + const struct _typelib_TypeDescription * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ); + + inline void acquire() const; + inline void release() const; +}; +} +#endif diff --git a/cli_ure/source/uno_bridge/cli_uno.cxx b/cli_ure/source/uno_bridge/cli_uno.cxx new file mode 100644 index 000000000000..34fdbe0c66ef --- /dev/null +++ b/cli_ure/source/uno_bridge/cli_uno.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cli_ure.hxx" + +#include <sal/alloca.h> +#include "rtl/ustrbuf.hxx" +#include "cli_base.h" +#include "cli_bridge.h" + +namespace sr=System::Reflection; +namespace css=com::sun::star; +using namespace rtl; + +namespace cli_uno +{ + +union largest +{ + sal_Int64 n; + double d; + void * p; + uno_Any a; +}; + +System::Object* Bridge::call_uno(uno_Interface * pUnoI, + typelib_TypeDescription* member_td, + typelib_TypeDescriptionReference * return_type, + sal_Int32 nParams, typelib_MethodParameter const * pParams, + System::Object * args[], System::Type* argTypes[], + System::Object** ppExc) const +{ + // return mem + sal_Int32 return_size = sizeof (largest); + if ((0 != return_type) && + (typelib_TypeClass_STRUCT == return_type->eTypeClass || + typelib_TypeClass_EXCEPTION == return_type->eTypeClass)) + { + TypeDescr return_td( return_type ); + if (return_td.get()->nSize > sizeof (largest)) + return_size = return_td.get()->nSize; + } + //Prepare memory that contains all converted arguments and return valuse + //The memory block contains first pointers to the arguments which are in the same block + // For example, 2 arguments, 1 ret. + // + // | Pointer + // | Pointer + // | Return value + // | Arg 1 + // | Arg 2 + // + // If an argument is larger then union largest, such as some structures, then the pointer + // points to an extra block of memory. The same goes for a big return value. + + char * mem = (char *)alloca( + (nParams * sizeof (void *)) + return_size + (nParams * sizeof (largest)) ); + //array of pointers to args + void ** uno_args = (void **)mem; + //If an attribute is set, then uno_ret must be null, e.g void setAttribute(int ) + void * uno_ret= NULL; + if ( !(member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE && nParams == 1)) + uno_ret = (mem + (nParams * sizeof (void *))); + largest * uno_args_mem = (largest *)(mem + (nParams * sizeof (void *)) + return_size); + + OSL_ASSERT( (0 == nParams) || (nParams == args->get_Length()) ); + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + typelib_TypeDescriptionReference * type = param.pTypeRef; + + uno_args[ nPos ] = &uno_args_mem[ nPos ]; + if (typelib_TypeClass_STRUCT == type->eTypeClass || + typelib_TypeClass_EXCEPTION == type->eTypeClass) + { + TypeDescr td( type ); + if (td.get()->nSize > sizeof (largest)) + uno_args[ nPos ] = alloca( td.get()->nSize ); + } + + if (param.bIn) + { + try + { + // in, in/out params + map_to_uno( + uno_args[ nPos ],args[nPos] , type, false /* no assign */); + } + catch (...) + { + // cleanup uno in args + for (sal_Int32 n = 0; n < nPos; ++n) + { + typelib_MethodParameter const & param = pParams[n]; + if (param.bIn) + { + uno_type_destructData(uno_args[n], param.pTypeRef, 0); + } + } + throw; + } + } + } + uno_Any uno_exc_holder; + uno_Any * uno_exc = &uno_exc_holder; + // call binary uno + + (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc ); + + if (0 == uno_exc) + { + // convert out args; destruct uno args + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + typelib_TypeDescriptionReference * type = param.pTypeRef; + if (param.bOut) + { + try + { + map_to_cli( + &args[nPos], uno_args[nPos], param.pTypeRef, + argTypes != NULL ? argTypes[nPos] : NULL, false ); + } + catch (...) + { + // cleanup further uno args + for ( sal_Int32 n = nPos; n < nParams; ++n ) + { + uno_type_destructData( uno_args[n], pParams[n].pTypeRef, 0 ); + } + // cleanup uno return value + uno_type_destructData( uno_ret, return_type, 0 ); + throw; + } + } + //cleanup args + if (typelib_TypeClass_DOUBLE < type->eTypeClass && + typelib_TypeClass_ENUM != type->eTypeClass) // opt + { + uno_type_destructData(uno_args[nPos], type, 0); + } + } + + if ((0 != return_type) && + (typelib_TypeClass_VOID != return_type->eTypeClass)) + { + // convert uno return value + try + { + System::Object* cli_ret; + map_to_cli( + &cli_ret, uno_ret, return_type, 0, false); + uno_type_destructData(uno_ret, return_type, 0); + return cli_ret; + } + catch (...) + { + uno_type_destructData(uno_ret, return_type, 0); + throw; + } + } + return 0; // void return + } + else // exception occured + { + // destruct uno in args + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = pParams[ nPos ]; + if (param.bIn) + { + uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 ); + } + } + map_to_cli(ppExc, uno_exc_holder.pData, + uno_exc_holder.pType, NULL, false); + return 0; + } +} + +void Bridge::call_cli( + System::Object* cliI, + sr::MethodInfo* method, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, int nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const +{ + System::Object *args[]= new System::Object*[nParams]; + for (int nPos= 0; nPos < nParams; nPos++) + { + typelib_MethodParameter const & param= params[nPos]; + if (param.bIn) + { + map_to_cli( &args[nPos], + uno_args[nPos], param.pTypeRef, 0, false); + } + } + System::Object* retInvoke= NULL; + try + { + retInvoke= method->Invoke(cliI, args); + } + catch (sr::TargetInvocationException* e) + { + System::Exception* exc= e->get_InnerException(); + css::uno::TypeDescription td(mapCliType(exc->GetType())); + // memory for exception + std::auto_ptr< rtl_mem > memExc(rtl_mem::allocate(td.get()->nSize)); + map_to_uno(memExc.get(), exc, td.get()->pWeakRef, false); + (*uno_exc)->pType= td.get()->pWeakRef; + (*uno_exc)->pData= memExc.release(); + return; + } + catch (System::Exception* e) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "Unexspected exception during invocation of cli object. " + "Original message is: \n") ); + buf.append(mapCliString(e->get_Message())); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + //convert out, in/out params + for (int nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = params[ nPos ]; + + if (param.bOut) + { + try + { + map_to_uno( + uno_args[ nPos ], args[ nPos ], param.pTypeRef, + sal_True == param.bIn /* assign if inout */); + // out array + } + catch (...) + { + // cleanup uno pure out + for ( sal_Int32 n = 0; n < nPos; ++n ) + { + typelib_MethodParameter const & param = params[ n ]; + if (! param.bIn) + uno_type_destructData( uno_args[ n ], param.pTypeRef, 0 ); + } + throw; + } + } + } + // return value + if (0 != return_type) + { + map_to_uno( + uno_ret, retInvoke, return_type, false /* no assign */); + } + // no exception occured + *uno_exc = 0; +} + + + + +} diff --git a/cli_ure/source/uno_bridge/makefile.mk b/cli_ure/source/uno_bridge/makefile.mk new file mode 100644 index 000000000000..b7682aed4b1b --- /dev/null +++ b/cli_ure/source/uno_bridge/makefile.mk @@ -0,0 +1,95 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/.. +PRJNAME = cli_ure + +TARGET = cli_uno +NO_BSYMBOLIC = TRUE +ENABLE_EXCEPTIONS = TRUE +USE_DEFFILE = TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + + +.IF "$(COM)" == "MSC" +# When compiling for CLR, disable "warning C4339: use of undefined type detected +# in CLR meta-data - use of this type may lead to a runtime exception": +.IF "$(CCNUMVER)" <= "001399999999" +CFLAGSCXX += -clr -AI $(DLLDEST) -AI $(SOLARBINDIR) -wd4339 +.ELSE +CFLAGSCXX += -clr:oldSyntax -AI $(DLLDEST) -AI $(SOLARBINDIR) -wd4339 +.ENDIF + +.IF "$(debug)" != "" +CFLAGS += -Ob0 +.ENDIF + + + +.IF "$(CCNUMVER)" <= "001399999999" +#see Microsoft Knowledge Base Article - 814472 +LINKFLAGS += -NOENTRY -NODEFAULTLIB:nochkclr.obj -INCLUDE:__DllMainCRTStartup@12 +.ENDIF +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/cli_environment.obj \ + $(SLO)$/cli_bridge.obj \ + $(SLO)$/cli_data.obj \ + $(SLO)$/cli_proxy.obj \ + $(SLO)$/cli_uno.obj + +SHL1OBJS = $(SLOFILES) + +SHL1TARGET = $(TARGET) + +SHL1STDLIBS = \ + $(CPPULIB) \ + $(SALLIB) \ + mscoree.lib + +.IF "$(CCNUMVER)" >= "001399999999" +SHL1STDLIBS += \ + msvcmrt.lib +.ENDIF + +SHL1VERSIONMAP = bridge_exports.map + +SHL1IMPLIB = i$(TARGET) +SHL1LIBS = $(SLB)$/$(TARGET).lib +SHL1DEF = $(MISC)$/$(SHL1TARGET).def +DEF1NAME = $(SHL1TARGET) + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk |