summaryrefslogtreecommitdiffstats
path: root/cli_ure/source/uno_bridge
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /cli_ure/source/uno_bridge
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'cli_ure/source/uno_bridge')
-rw-r--r--cli_ure/source/uno_bridge/README.txt20
-rw-r--r--cli_ure/source/uno_bridge/cli_base.h171
-rw-r--r--cli_ure/source/uno_bridge/cli_bridge.cxx321
-rw-r--r--cli_ure/source/uno_bridge/cli_bridge.h113
-rw-r--r--cli_ure/source/uno_bridge/cli_data.cxx1929
-rw-r--r--cli_ure/source/uno_bridge/cli_environment.cxx168
-rw-r--r--cli_ure/source/uno_bridge/cli_environment.h105
-rw-r--r--cli_ure/source/uno_bridge/cli_proxy.cxx1105
-rw-r--r--cli_ure/source/uno_bridge/cli_proxy.h294
-rw-r--r--cli_ure/source/uno_bridge/cli_uno.cxx277
10 files changed, 4503 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 000000000..39b3ce364
--- /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/cli_base.h b/cli_ure/source/uno_bridge/cli_base.h
new file mode 100644
index 000000000..bca780f7c
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_base.h
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_BASE_H
+#define INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_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 <system.dll>
+
+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);
+OUString mapCliString(System::String ^ data);
+System::String^ mapUnoString(rtl_uString const * data);
+System::String^ mapUnoTypeName(rtl_uString const * typeName);
+
+ref struct Constants
+{
+ static System::String^ sXInterfaceName= gcnew System::String(
+ "unoidl.com.sun.star.uno.XInterface");
+ static System::String^ sObject= gcnew System::String("System.Object");
+ static System::String^ sType= gcnew System::String("System.Type");
+ static System::String^ sUnoidl= gcnew System::String("unoidl.");
+ static System::String^ sVoid= gcnew System::String("System.Void");
+ static System::String^ sAny= gcnew System::String("uno.Any");
+ static System::String^ sArArray= gcnew System::String("System.Array[]");
+ static System::String^ sBoolean= gcnew System::String("System.Boolean");
+ static System::String^ sChar= gcnew System::String("System.Char");
+ static System::String^ sByte= gcnew System::String("System.Byte");
+ static System::String^ sInt16= gcnew System::String("System.Int16");
+ static System::String^ sUInt16= gcnew System::String("System.UInt16");
+ static System::String^ sInt32= gcnew System::String("System.Int32");
+ static System::String^ sUInt32= gcnew System::String("System.UInt32");
+ static System::String^ sInt64= gcnew System::String("System.Int64");
+ static System::String^ sUInt64= gcnew System::String("System.UInt64");
+ static System::String^ sString= gcnew System::String("System.String");
+ static System::String^ sSingle= gcnew System::String("System.Single");
+ static System::String^ sDouble= gcnew System::String("System.Double");
+ static System::String^ sArBoolean= gcnew System::String("System.Boolean[]");
+ static System::String^ sArChar= gcnew System::String("System.Char[]");
+ static System::String^ sArByte= gcnew System::String("System.Byte[]");
+ static System::String^ sArInt16= gcnew System::String("System.Int16[]");
+ static System::String^ sArUInt16= gcnew System::String("System.UInt16[]");
+ static System::String^ sArInt32= gcnew System::String("System.Int32[]");
+ static System::String^ sArUInt32= gcnew System::String("System.UInt32[]");
+ static System::String^ sArInt64= gcnew System::String("System.Int64[]");
+ static System::String^ sArUInt64= gcnew System::String("System.UInt64[]");
+ static System::String^ sArString= gcnew System::String("System.String[]");
+ static System::String^ sArSingle= gcnew System::String("System.Single[]");
+ static System::String^ sArDouble= gcnew System::String("System.Double[]");
+ static System::String^ sArType= gcnew System::String("System.Type[]");
+ static System::String^ sArObject= gcnew System::String("System.Object[]");
+ static System::String^ sBrackets= gcnew System::String("[]");
+ static System::String^ sAttributeSet= gcnew System::String("set_");
+ static System::String^ sAttributeGet= gcnew System::String("get_");
+
+ static System::String^ usXInterface = "com.sun.star.uno.XInterface";
+ static System::String^ usVoid = "void";
+ static System::String^ usType = "type";
+ static System::String^ usAny = "any";
+ static System::String^ usBrackets = "[]";
+ static System::String^ usBool = "boolean";
+ static System::String^ usByte = "byte";
+ static System::String^ usChar = "char";
+ static System::String^ usShort = "short";
+ static System::String^ usUShort = "unsigned short";
+ static System::String^ usLong = "long";
+ static System::String^ usULong = "unsigned long";
+ static System::String^ usHyper = "hyper";
+ static System::String^ usUHyper = "unsigned hyper";
+ static System::String^ usString = "string";
+ static System::String^ usFloat = "float";
+ static System::String^ usDouble = "double";
+};
+
+struct BridgeRuntimeError
+{
+ OUString m_message;
+
+ inline BridgeRuntimeError( OUString const & message )
+ : m_message( message )
+ {}
+};
+
+
+struct rtl_mem
+{
+ inline static void * operator new ( size_t nSize )
+ { return std::malloc( nSize ); }
+ inline static void operator delete ( void * mem )
+ { std::free( mem ); }
+ inline static void * operator new ( size_t, void * mem )
+ { return mem; }
+ inline static void operator delete ( void *, void * )
+ {}
+
+ static inline std::unique_ptr< rtl_mem > allocate( std::size_t bytes );
+};
+
+inline std::unique_ptr< rtl_mem > rtl_mem::allocate( std::size_t bytes )
+{
+ void * p = std::malloc( bytes );
+ if (0 == p)
+ throw BridgeRuntimeError("out of memory!" );
+ return std::unique_ptr< rtl_mem >( (rtl_mem *)p );
+}
+
+
+class TypeDescr
+{
+ typelib_TypeDescription * m_td;
+
+ TypeDescr( TypeDescr const & ) = delete;
+ TypeDescr& operator = ( TypeDescr const & ) = delete;
+
+public:
+ inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref );
+ inline ~TypeDescr()
+ { 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(
+ "cannot get comprehensive type description for " +
+ OUString::unacquired(&td_ref->pTypeName) );
+ }
+}
+
+
+} //end namespace cli_uno
+ #endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..d9b4cdd0b
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_bridge.cxx
@@ -0,0 +1,321 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcclr.h>
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include "uno/environment.hxx"
+#include "uno/lbnames.h"
+#include "uno/mapping.hxx"
+#include "typelib/typedescription.hxx"
+#include "rtl/ustring.hxx"
+#include <sal/log.hxx>
+
+#include "cli_bridge.h"
+#include "cli_proxy.h"
+
+namespace sri= System::Runtime::InteropServices;
+
+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::FromIntPtr(IntPtr(cliI)).Target;
+ (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td);
+ }
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ (void) err;
+ SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
+ }
+}
+
+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::FromIntPtr(IntPtr(ppDNetI)).Free();
+ }
+
+ if (0 != pUnoI)
+ {
+ System::Object^ cliI= bridge->map_uno2cli(pUnoI, td);
+ intptr_t ptr= NULL;
+ if(cliI)
+ {
+ ptr= sri::GCHandle::ToIntPtr(sri::GCHandle::Alloc(cliI))
+#ifdef _WIN64
+ .ToInt64();
+#else /* defined(_WIN32) */
+ .ToInt32();
+#endif
+ }
+ (*ppOut)= reinterpret_cast<void*>(ptr);
+ }
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ (void) err;
+ SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
+ }
+}
+
+
+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 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 no one has
+ a reference to the object anymore. Hence no one can call acquire. If someone
+ calls acquire then they must have kept an unacquired pointer which is
+ illegal.
+ */
+void Bridge::acquire() const
+{
+ if (1 == osl_atomic_increment( &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
+{
+ if (! osl_atomic_decrement( &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()
+{
+ //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;
+}
+
+
+SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env )
+ SAL_THROW_EXTERN_C()
+{
+ //ToDo: remove when compiled with .NET 2
+
+ // Unclear whether the above comment refers to this whole function
+ // or a call to __crt_dll_initialize() that used to be here for
+ // _MSC_VER < 1400
+
+ 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::Listeners->
+ Add( gcnew System::Diagnostics::TextWriterTraceListener(System::Console::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 = gcnew Cli_environment();
+}
+
+SAL_DLLPUBLIC_EXPORT 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 = OUString::unacquired(
+ &pFrom->pTypeName );
+ OUString const & to_env_typename = OUString::unacquired( &pTo->pTypeName );
+
+ uno_Mapping * mapping = 0;
+
+ try
+ {
+ if ( from_env_typename == UNO_LB_CLI && to_env_typename == 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 == UNO_LB_UNO && to_env_typename == 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)
+ {
+ (void) err;
+ SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
+ }
+ *ppMapping = mapping;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..95ddb0394
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_bridge.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_BRIDGE_H
+#define INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_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 <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 a UNO proxies (which are cli
+//objects. The uno_Environment is not used for cli objects.
+ref struct CliEnvHolder {
+static Cli_environment ^ g_cli_env = nullptr;
+};
+
+
+/** 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();
+ 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^ call_uno(uno_Interface * pUnoI,
+ typelib_TypeDescription* member_td,
+ typelib_TypeDescriptionReference * return_type,
+ sal_Int32 nParams, typelib_MethodParameter const * pParams,
+ array<System::Object^>^ args, array<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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..72b39df48
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_data.cxx
@@ -0,0 +1,1929 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include "windows.h"
+#include <ole2.h>
+
+#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 sri = System::Runtime::InteropServices;
+namespace sr = System::Reflection;
+namespace st = System::Text;
+namespace ucss = unoidl::com::sun::star;
+
+
+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 std::unique_ptr< rtl_mem > seq_allocate( sal_Int32 nElements, sal_Int32 nSize )
+{
+ std::unique_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= nullptr;
+ // 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 a 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(Cli_environment::typeid);
+ 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(Cli_environment::typeid);
+ }
+ }
+ return retIface;
+}
+
+inline System::Type^ loadCliType(rtl_uString * unoName)
+{
+ return loadCliType(mapUnoTypeName(unoName));
+}
+
+System::Type^ loadCliType(System::String ^ unoName)
+{
+ System::Type^ retVal= nullptr;
+ 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;
+ cli::array<sr::Assembly^>^ assems = currentDomain->GetAssemblies();
+ for (int i = 0; i < assems->Length; i++)
+ {
+ retVal = assems[i]->GetType(loadName, false);
+ if (retVal)
+ break;
+ }
+
+ if (retVal == nullptr)
+ {
+ System::String ^ msg = gcnew System::String("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)
+ {
+ OUString ouMessage(mapCliString(e->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 = nullptr;
+ switch (pTD->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ retVal= void::typeid; break;
+ case typelib_TypeClass_CHAR:
+ retVal= System::Char::typeid; break;
+ case typelib_TypeClass_BOOLEAN:
+ retVal= System::Boolean::typeid; break;
+ case typelib_TypeClass_BYTE:
+ retVal= System::Byte::typeid; break;
+ case typelib_TypeClass_SHORT:
+ retVal= System::Int16::typeid; break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ retVal= System::UInt16::typeid; break;
+ case typelib_TypeClass_LONG:
+ retVal= System::Int32::typeid; break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ retVal= System::UInt32::typeid; break;
+ case typelib_TypeClass_HYPER:
+ retVal= System::Int64::typeid; break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ retVal= System::UInt64::typeid; break;
+ case typelib_TypeClass_FLOAT:
+ retVal= System::Single::typeid; break;
+ case typelib_TypeClass_DOUBLE:
+ retVal= System::Double::typeid; break;
+ case typelib_TypeClass_STRING:
+ retVal= System::String::typeid; break;
+ case typelib_TypeClass_TYPE:
+ retVal= System::Type::typeid; break;
+ case typelib_TypeClass_ANY:
+ retVal= uno::Any::typeid; 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.
+ OUString usXInterface("com.sun.star.uno.XInterface");
+ if (usXInterface.equals(pTD->pTypeName))
+ retVal= System::Object::typeid;
+ 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 == nullptr)
+ {
+ 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->IsEnum)
+ {
+ OUString usTypeName= mapCliTypeName(cliType->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->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 != nullptr)
+ 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)
+ {
+ throw BridgeRuntimeError("[cli_uno bridge] mapCliType():could not map type: " + mapCliString(cliType->FullName));
+ }
+ 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= gcnew 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);
+ }
+ // append []
+ 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 prefix 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 prefix 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 = gcnew 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 need 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[cur];
+ if (c == ',' || c == '>')
+ {
+ //insert a comma if needed
+ if (countParams != 0)
+ builder->Append(",");
+ countParams++;
+ System::String ^ sParam = unoName->Substring(index, cur - index);
+ //skip the comma
+ cur++;
+ //the index to the beginning of the next param
+ index = cur;
+ if (bCliToUno)
+ {
+ builder->Append(mapCliTypeName(sParam).getStr());
+ }
+ 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[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[cur];
+ if (c == ']')
+ {
+ bRightBracket = true;
+ }
+ else if (c == '[')
+ {
+ if (!bRightBracket)
+ throw BridgeRuntimeError(
+ "Typename is wrong. No matching brackets for sequence. Name is: " +
+ mapCliString(typeName));
+ bRightBracket = false;
+ dims ++;
+ }
+ else
+ {
+ if (bRightBracket)
+ throw BridgeRuntimeError(
+ "Typename is wrong. No matching brackets for sequence. Name is: " +
+ mapCliString(typeName));
+ break;
+ }
+ cur--;
+ }
+
+ if (bRightBracket || cur < 0)
+ throw BridgeRuntimeError(
+ "Typename is wrong. " +
+ mapCliString(typeName));
+
+ typeName = typeName->Substring(0, cur + 1);
+
+ System::Text::StringBuilder ^ buf = gcnew 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 gcnew System::String((__wchar_t*) data->buffer, 0, data->length);
+}
+
+OUString mapCliString(System::String ^ data)
+{
+
+ if (data != nullptr)
+ {
+ static_assert(sizeof(wchar_t) == sizeof(sal_Unicode), "char mismatch");
+ pin_ptr<wchar_t const> pdata= PtrToStringChars(data);
+ return OUString(
+ reinterpret_cast<sal_Unicode const *>(pdata),
+ const_cast<System::String^>(data)->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= *safe_cast<System::Char^>(cli_data);
+ *(sal_Unicode*) uno_data= aChar;
+ break;
+ }
+ case typelib_TypeClass_BOOLEAN:
+ {
+ System::Boolean aBool= *safe_cast<System::Boolean^>(cli_data);
+ *(sal_Bool*)uno_data= aBool == true ? sal_True : sal_False;
+ break;
+ }
+ case typelib_TypeClass_BYTE:
+ {
+ System::Byte aByte= *safe_cast<System::Byte^>(cli_data);
+ *(sal_Int8*) uno_data= aByte;
+ break;
+ }
+ case typelib_TypeClass_SHORT:
+ {
+ System::Int16 aShort= *safe_cast<System::Int16^>(cli_data);
+ *(sal_Int16*) uno_data= aShort;
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ {
+ System::UInt16 aUShort= *safe_cast<System::UInt16^>(cli_data);
+ *(sal_uInt16*) uno_data= aUShort;
+ break;
+ }
+ case typelib_TypeClass_LONG:
+ {
+ System::Int32 aLong= *safe_cast<System::Int32^>(cli_data);
+ *(sal_Int32*) uno_data= aLong;
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ {
+ System::UInt32 aULong= *safe_cast<System::UInt32^>(cli_data);
+ *(sal_uInt32*) uno_data= aULong;
+ break;
+ }
+ case typelib_TypeClass_HYPER:
+ {
+ System::Int64 aHyper= *safe_cast<System::Int64^>(cli_data);
+ *(sal_Int64*) uno_data= aHyper;
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ System::UInt64 aLong= *safe_cast<System::UInt64^>(cli_data);
+ *(sal_uInt64*) uno_data= aLong;
+ break;
+ }
+ case typelib_TypeClass_FLOAT:
+ {
+ System::Single aFloat= *safe_cast<System::Single^>(cli_data);
+ *(float*) uno_data= aFloat;
+ break;
+ }
+ case typelib_TypeClass_DOUBLE:
+ {
+ System::Double aDouble= *safe_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 == nullptr)
+ {
+ rtl_uString_new((rtl_uString**) uno_data);
+ }
+ else
+ {
+ System::String ^s= safe_cast<System::String^>(cli_data);
+ pin_ptr<const wchar_t> pdata= PtrToStringChars(s);
+ rtl_uString_newFromStr_WithLength(
+ reinterpret_cast<rtl_uString **>(uno_data),
+ reinterpret_cast<sal_Unicode const *>(pdata), s->Length);
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ typelib_TypeDescriptionReference* td= mapCliType(safe_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 == nullptr) // 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= *safe_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 css::uno::TypeClass_VOID:
+ pAny->pData = &pAny->pReserved;
+ break;
+ case css::uno::TypeClass_CHAR:
+ pAny->pData = &pAny->pReserved;
+ *(sal_Unicode*) &pAny->pReserved = *safe_cast<System::Char^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_BOOLEAN:
+ pAny->pData = &pAny->pReserved;
+ *(sal_Bool *) &pAny->pReserved = *safe_cast<System::Boolean^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_BYTE:
+ pAny->pData = &pAny->pReserved;
+ *(sal_Int8*) &pAny->pReserved = *safe_cast<System::Byte^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_SHORT:
+ pAny->pData = &pAny->pReserved;
+ *(sal_Int16*) &pAny->pReserved = *safe_cast<System::Int16^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_UNSIGNED_SHORT:
+ pAny->pData = &pAny->pReserved;
+ *(sal_uInt16*) &pAny->pReserved = *safe_cast<System::UInt16^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_LONG:
+ pAny->pData = &pAny->pReserved;
+ *(sal_Int32*) &pAny->pReserved = *safe_cast<System::Int32^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_UNSIGNED_LONG:
+ pAny->pData = &pAny->pReserved;
+ *(sal_uInt32*) &pAny->pReserved = *safe_cast<System::UInt32^>(aAny.Value);
+ break;
+ case css::uno::TypeClass_HYPER:
+ if (sizeof (sal_Int64) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *(sal_Int64*) &pAny->pReserved = *safe_cast<System::Int64^>(aAny.Value);
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_Int64) ) );
+ *(sal_Int64 *) mem.get()= *safe_cast<System::Int64^>(aAny.Value);
+ pAny->pData = mem.release();
+ }
+ break;
+ case css::uno::TypeClass_UNSIGNED_HYPER:
+ if (sizeof (sal_uInt64) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *(sal_uInt64*) &pAny->pReserved = *safe_cast<System::UInt64^>(aAny.Value);
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (sal_uInt64) ) );
+ *(sal_uInt64 *) mem.get()= *safe_cast<System::UInt64^>(aAny.Value);
+ pAny->pData = mem.release();
+ }
+ break;
+ case css::uno::TypeClass_FLOAT:
+ if (sizeof (float) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *(float*) &pAny->pReserved = *safe_cast<System::Single^>(aAny.Value);
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (float) ) );
+ *(float*) mem.get() = *safe_cast<System::Single^>(aAny.Value);
+ pAny->pData = mem.release();
+ }
+ break;
+ case css::uno::TypeClass_DOUBLE:
+ if (sizeof (double) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *(double*) &pAny->pReserved= *safe_cast<System::Double^>(aAny.Value);
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem( rtl_mem::allocate( sizeof (double) ) );
+ *(double*) mem.get()= *safe_cast<System::Double^>(aAny.Value);
+ pAny->pData= mem.release();
+ }
+ break;
+ case css::uno::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 css::uno::TypeClass_TYPE:
+ case css::uno::TypeClass_ENUM: //ToDo copy enum direct
+ case css::uno::TypeClass_SEQUENCE:
+ case css::uno::TypeClass_INTERFACE:
+ pAny->pData = &pAny->pReserved;
+ pAny->pReserved = 0;
+ map_to_uno(
+ &pAny->pReserved, aAny.Value, value_td.getTypeLibType(),
+ false /* no assign */);
+ break;
+ case css::uno::TypeClass_STRUCT:
+ case css::uno::TypeClass_EXCEPTION:
+ {
+ css::uno::Type anyType(value_td);
+ typelib_TypeDescription* td= NULL;
+ anyType.getDescription(&td);
+ std::unique_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:
+ {
+ throw BridgeRuntimeError("[map_to_uno():" + value_td.getTypeName() + "] unsupported value type of any!");
+ }
+ }
+ }
+ catch(System::InvalidCastException^ )
+ {
+// ToDo check this
+ if (assign)
+ uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any
+ OUString str = "[map_to_uno():Any" + value_td.getTypeName() + "]The Any type " + value_td.getTypeName() + " does not correspond to its value type: ";
+ if(aAny.Value != nullptr)
+ {
+ css::uno::Type td(mapCliType(aAny.Value->GetType()), SAL_NO_ACQUIRE);
+ str += td.getTypeName();
+ }
+ if (assign)
+ uno_any_construct( pAny, 0, 0, 0 ); // restore some valid any
+ throw BridgeRuntimeError(str);
+ }
+ 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 = nullptr;
+ 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
+ {
+ OUString usUnoException("com.sun.star.uno.Exception");
+ for (; nPos < nMembers; ++nPos)
+ {
+ typelib_TypeDescriptionReference * member_type= comp_td->ppTypeRefs[nPos];
+ System::Object^ val= nullptr;
+ if (cli_data != nullptr)
+ {
+ 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
+ OUString usMessageMember("Message");
+ if (usMessageMember.equals(comp_td->ppMemberNames[nPos]))
+ {
+ sr::PropertyInfo^ pi= cliType->GetProperty(
+ mapUnoString(comp_td->ppMemberNames[nPos]));
+ val= pi->GetValue(cli_data, nullptr);
+ }
+ else
+ {
+ throw BridgeRuntimeError("[map_to_uno(): Member: " + OUString::unacquired(&comp_td->ppMemberNames[nPos]));
+ }
+ }
+ 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 == nullptr)
+ || cli_data == nullptr;
+ switch (member_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (bDefault)
+ *(sal_Unicode*) p = 0;
+ else
+ *(sal_Unicode*) p = *safe_cast<System::Char^>(val);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (bDefault)
+ *(sal_Bool*) p = sal_False;
+ else
+ *(sal_Bool*) p = *safe_cast<System::Boolean^>(val);
+ break;
+ case typelib_TypeClass_BYTE:
+ if (bDefault)
+ *(sal_Int8*) p = 0;
+ else
+ *(sal_Int8*) p = *safe_cast<System::Byte^>(val);
+ break;
+ case typelib_TypeClass_SHORT:
+ if (bDefault)
+ *(sal_Int16*) p = 0;
+ else
+ *(sal_Int16*) p = *safe_cast<System::Int16^>(val);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (bDefault)
+ *(sal_uInt16*) p = 0;
+ else
+ *(sal_uInt16*) p = *safe_cast<System::UInt16^>(val);
+ break;
+ case typelib_TypeClass_LONG:
+ if (bDefault)
+ *(sal_Int32*) p = 0;
+ else
+ *(sal_Int32*) p = *safe_cast<System::Int32^>(val);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (bDefault)
+ *(sal_uInt32*) p = 0;
+ else
+ *(sal_uInt32*) p = *safe_cast<System::UInt32^>(val);
+ break;
+ case typelib_TypeClass_HYPER:
+ if (bDefault)
+ *(sal_Int64*) p = 0;
+ else
+ *(sal_Int64*) p = *safe_cast<System::Int64^>(val);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (bDefault)
+ *(sal_uInt64*) p = 0;
+ else
+ *(sal_uInt64*) p= *safe_cast<System::UInt64^>(val);
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (bDefault)
+ *(float*) p = 0.;
+ else
+ *(float*) p = *safe_cast<System::Single^>(val);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (bDefault)
+ *(double*) p = 0.;
+ else
+ *(double*) p = *safe_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;
+ OUString str = "[map_to_uno():";
+ if (cliType)
+ {
+ str += mapCliString(cliType->FullName) + "." + OUString::unacquired(&comp_td->ppMemberNames[nPos]) + " ";
+ }
+ str += e.m_message;
+ throw BridgeRuntimeError(str);
+ }
+ catch (System::InvalidCastException^ )
+ {
+ bException= true;
+ OUString str = "[map_to_uno():";
+ if (cliType)
+ {
+ str += mapCliString(cliType->FullName) + "." + OUString::unacquired(&comp_td->ppMemberNames[nPos]);
+ }
+ str += "] Value has not the required type.";
+ throw BridgeRuntimeError(str);
+ }
+ 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;
+
+ std::unique_ptr< rtl_mem > seq;
+
+ System::Array^ ar = nullptr;
+ if (cli_data != nullptr)
+ {
+ ar = safe_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(safe_cast<cli::array<System::Char>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ seq = seq_allocate(nElements, sizeof (sal_Bool));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Char>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_BYTE:
+ seq = seq_allocate( nElements, sizeof (sal_Int8) );
+ sri::Marshal::Copy(safe_cast<cli::array<System::Byte>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_SHORT:
+ seq = seq_allocate(nElements, sizeof (sal_Int16));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Int16>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ seq = seq_allocate( nElements, sizeof (sal_uInt16) );
+ sri::Marshal::Copy(dynamic_cast<cli::array<System::Int16>^>(
+ safe_cast<cli::array<System::UInt16>^>(cli_data)), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_LONG:
+ seq = seq_allocate(nElements, sizeof (sal_Int32));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Int32>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ seq = seq_allocate( nElements, sizeof (sal_uInt32) );
+ sri::Marshal::Copy(dynamic_cast<cli::array<System::Int32>^>(
+ safe_cast<cli::array<System::UInt32>^>(cli_data)), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_HYPER:
+ seq = seq_allocate(nElements, sizeof (sal_Int64));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Int64>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ seq = seq_allocate(nElements, sizeof (sal_uInt64));
+ sri::Marshal::Copy(dynamic_cast<cli::array<System::Int64>^>(
+ safe_cast<cli::array<System::UInt64>^>(cli_data)), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_FLOAT:
+ seq = seq_allocate(nElements, sizeof (float));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Single>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ seq = seq_allocate(nElements, sizeof (double));
+ sri::Marshal::Copy(safe_cast<cli::array<System::Double>^>(cli_data), 0,
+ IntPtr(& ((uno_Sequence*) seq.get())->elements), nElements);
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ seq = seq_allocate(nElements, sizeof (rtl_uString*));
+ cli::array<System::String^>^ arStr= safe_cast<cli::array<System::String^>^>(cli_data);
+ for (int i= 0; i < nElements; i++)
+ {
+ pin_ptr<const wchar_t> pdata= PtrToStringChars(arStr[i]);
+ rtl_uString** pStr= & ((rtl_uString**) &
+ ((uno_Sequence*) seq.get())->elements)[i];
+ *pStr= NULL;
+ rtl_uString_newFromStr_WithLength(
+ pStr,
+ reinterpret_cast<sal_Unicode const *>(pdata),
+ arStr[i]->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= safe_cast<System::Array^>(cli_data)->GetValue(System::Int32(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:
+ {
+ throw BridgeRuntimeError("[map_to_uno():" + OUString::unacquired( &type->pTypeName ) +
+ "] unsupported sequence element type: " + OUString::unacquired( &element_type->pTypeName ));
+ }
+ }
+ }
+ catch (BridgeRuntimeError& e)
+ {
+ throw BridgeRuntimeError("[map_to_uno():" + OUString::unacquired( &type->pTypeName ) + "] conversion failed\n " + e.m_message);
+ }
+ catch (System::InvalidCastException^ )
+ {
+ // Ok, checked
+ throw BridgeRuntimeError("[map_to_uno():" + OUString::unacquired( &type->pTypeName) +
+ "] could not convert sequence element type: " + OUString::unacquired( &element_type->pTypeName ));
+ }
+ 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 (nullptr == 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
+ throw BridgeRuntimeError("[map_to_uno():" + OUString::unacquired( &type->pTypeName ) + "] unsupported type!");
+ }
+ }
+ }
+ // BridgeRuntimeError are allowed to be thrown
+ catch (System::InvalidCastException^ )
+ {
+ //ToDo check
+ throw BridgeRuntimeError("[map_to_uno():" + OUString::unacquired( &type->pTypeName ) + "] could not convert type!");
+ }
+ catch (System::NullReferenceException ^ e)
+ {
+ throw BridgeRuntimeError("[map_to_uno()] Illegal null reference passed!\n" + mapCliString(e->StackTrace));
+ }
+ catch (BridgeRuntimeError& )
+ {
+ throw;
+ }
+ catch (...)
+ {
+ OSL_ASSERT(0);
+ throw;
+ }
+}
+
+/**
+ @param info
+ The expected target type. Currently info is provided 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 recursively 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= *(__wchar_t const*)uno_data;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ *cli_data = (*(bool const*)uno_data) == sal_True;
+ break;
+ case typelib_TypeClass_BYTE:
+ *cli_data = *(unsigned char const*) uno_data;
+ break;
+ case typelib_TypeClass_SHORT:
+ *cli_data= *(short const*) uno_data;
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *cli_data= *(unsigned short const*) uno_data;
+ break;
+ case typelib_TypeClass_LONG:
+ *cli_data= *(int const*) uno_data;
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *cli_data= *(unsigned int const*) uno_data;
+ break;
+ case typelib_TypeClass_HYPER:
+ *cli_data= *(__int64 const*) uno_data;
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *cli_data= *(unsigned __int64 const*) uno_data;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *cli_data= *(float const*) uno_data;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *cli_data= *(double const*) uno_data;
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ rtl_uString const* sVal= NULL;
+ sVal= *(rtl_uString* const*) uno_data;
+ *cli_data= gcnew 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= nullptr;
+ map_to_cli(
+ &objCli, pAny->pData, pAny->pType, nullptr,
+ false);
+
+ uno::Any anyVal(mapUnoType(pAny->pType), objCli);
+ *cli_data= anyVal;
+ }
+ else
+ { // void any
+ *cli_data= uno::Any::VOID;
+ }
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ if (info != nullptr)
+ {
+ OSL_ASSERT(info->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 recursively convert inherited structures
+ //If this point is reached because of a recursive call during covering 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 (ucss::uno::Exception::typeid->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;
+
+ OUString usMessageMember("Message");
+ for (int i = 0; i < pCTD->nMembers; i ++)
+ {
+ if (usMessageMember.equals(pCTD->ppMemberNames[i]))
+ {
+ nPos = i;
+ break;
+ }
+ }
+ OSL_ASSERT (nPos != -1);
+ int offset = pCTD->pMemberOffsets[nPos];
+ //With 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
+ cli::array<sr::ConstructorInfo^>^ arCtorInfo = cliType->GetConstructors();
+ sr::ConstructorInfo^ ctorInfo = nullptr;
+ int numCtors = arCtorInfo->Length;
+ //Constructor must at least have 2 params for the base
+ //unoidl.com.sun.star.uno.Exception (String, Object);
+ cli::array<sr::ParameterInfo^>^ arParamInfo;
+ for (int i = 0; i < numCtors; i++)
+ {
+ arParamInfo = arCtorInfo[i]->GetParameters();
+ if (arParamInfo->Length < 2)
+ continue;
+ ctorInfo = arCtorInfo[i];
+ break;
+ }
+ OSL_ASSERT(arParamInfo[0]->ParameterType->Equals(System::String::typeid)
+ && arParamInfo[1]->ParameterType->Equals(System::Object::typeid)
+ && arParamInfo[0]->Position == 0
+ && arParamInfo[1]->Position == 1);
+ //Prepare parameters for constructor
+ int numArgs = arParamInfo->Length;
+ cli::array<System::Object^>^ args = gcnew cli::array<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, nullptr,
+ true);
+ }
+ OUString usUnoException("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, *(System::Char*) p);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ aField->SetValue(cliObj, *(System::Boolean*) p);
+ break;
+ case typelib_TypeClass_BYTE:
+ aField->SetValue(cliObj, *(System::Byte*) p);
+ break;
+ case typelib_TypeClass_SHORT:
+ aField->SetValue(cliObj, *(System::Int16*) p);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ aField->SetValue(cliObj, *(System::UInt16*) p);
+ break;
+ case typelib_TypeClass_LONG:
+ aField->SetValue(cliObj, *(System::Int32*) p);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ aField->SetValue(cliObj, *(System::UInt32*) p);
+ break;
+ case typelib_TypeClass_HYPER:
+ aField->SetValue(cliObj, *(System::Int64*) p);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ aField->SetValue(cliObj, *(System::UInt64*) p);
+ break;
+ case typelib_TypeClass_FLOAT:
+ aField->SetValue(cliObj, *(System::Single*) p);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ aField->SetValue(cliObj, *(System::Double*) p);
+ break;
+ default:
+ {
+ System::Object^ cli_val;
+ map_to_cli(
+ &cli_val, p, member_type, nullptr,
+ 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:
+ {
+ cli::array<System::Char>^ arChar= gcnew cli::array<System::Char>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arChar, 0, nElements);
+ *cli_data= arChar;
+ break;
+ }
+ case typelib_TypeClass_BOOLEAN:
+ {
+ cli::array<System::Byte>^ arBool= gcnew cli::array<System::Byte>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arBool, 0, nElements);
+ *cli_data= dynamic_cast<cli::array<System::Boolean>^>(arBool);
+ break;
+ }
+ case typelib_TypeClass_BYTE:
+ {
+ cli::array<System::Byte>^ arByte= gcnew cli::array<System::Byte>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arByte, 0, nElements);
+ *cli_data= arByte;
+ break;
+ }
+ case typelib_TypeClass_SHORT:
+ {
+ cli::array<System::Int16>^ arShort= gcnew cli::array<System::Int16>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arShort, 0, nElements);
+ *cli_data= arShort;
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ {
+ cli::array<System::UInt16>^ arUInt16= gcnew cli::array<System::UInt16>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), dynamic_cast<cli::array<System::Int16>^>(arUInt16),
+ 0, nElements);
+ *cli_data= arUInt16;
+ break;
+ }
+ case typelib_TypeClass_LONG:
+ {
+ cli::array<System::Int32>^ arInt32= gcnew cli::array<System::Int32>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arInt32, 0, nElements);
+ *cli_data= arInt32;
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ {
+ cli::array<System::UInt32>^ arUInt32= gcnew cli::array<System::UInt32>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), dynamic_cast<cli::array<System::Int32>^>(arUInt32),
+ 0, nElements);
+ *cli_data= arUInt32;
+ break;
+ }
+ case typelib_TypeClass_HYPER:
+ {
+ cli::array<System::Int64>^ arInt64= gcnew cli::array<System::Int64>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arInt64, 0, nElements);
+ *cli_data= arInt64;
+ break;
+ }
+ //FIXME: Marshal::Copy of UInt64?
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ cli::array<System::IntPtr>^ arUInt64= gcnew cli::array<System::IntPtr>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arUInt64, 0, nElements);
+ *cli_data= dynamic_cast<cli::array<System::UInt64>^>(arUInt64);
+ break;
+ }
+ case typelib_TypeClass_FLOAT:
+ {
+ cli::array<System::Single>^ arSingle= gcnew cli::array<System::Single>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arSingle, 0, nElements);
+ *cli_data= arSingle;
+ break;
+ }
+ case typelib_TypeClass_DOUBLE:
+ {
+ cli::array<System::Double>^ arDouble= gcnew cli::array<System::Double>(nElements);
+ sri::Marshal::Copy( IntPtr((void*) &seq->elements), arDouble, 0, nElements);
+ *cli_data= arDouble;
+ break;
+ }
+ case typelib_TypeClass_STRING:
+ {
+ cli::array<System::String^>^ arString= gcnew cli::array<System::String^>(nElements);
+ for (int i= 0; i < nElements; i++)
+ {
+ rtl_uString *aStr= ((rtl_uString**)(&seq->elements))[i];
+ arString[i]= gcnew System::String( (__wchar_t *) &aStr->buffer, 0, aStr->length);
+ }
+ *cli_data= arString;
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ cli::array<System::Type^>^ arType= gcnew cli::array<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:
+ {
+ cli::array<uno::Any>^ arCli= gcnew cli::array<uno::Any>(nElements);
+ uno_Any const * p = (uno_Any const *)seq->elements;
+ for (sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ System::Object^ cli_obj = nullptr;
+ map_to_cli(
+ &cli_obj, &p[ nPos ], element_type, nullptr, false);
+ arCli[nPos]= *safe_cast<uno::Any^>(cli_obj);
+ }
+ *cli_data= arCli;
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ //get the Enum type
+ System::Type^ enumType= nullptr;
+ if (info != nullptr)
+ {
+ //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,
+ System::Int32(((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, nullptr, false);
+ ar->SetValue(val, System::Int32(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, nullptr, false);
+ ar->SetValue(val, System::Int32(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, nullptr, false);
+
+ ar->SetValue(val, System::Int32(nPos));
+ }
+ *cli_data= ar;
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError("[map_to_cli():" + OUString::unacquired( &type->pTypeName ) +
+ "] unsupported element type: " + OUString::unacquired( &element_type->pTypeName ));
+ }
+ }
+ 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= nullptr;
+ break;
+ }
+ default:
+ {
+ //ToDo check this exception. The String is probably crippled
+ throw BridgeRuntimeError("[map_to_cli():" + OUString::unacquired( &type->pTypeName ) + "] unsupported type!");
+ }
+ } //switch
+} // method
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..3c054b5be
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_environment.cxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "Cli_environment.h"
+
+#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->FullName);
+}
+
+
+inline Cli_environment::Cli_environment()
+{
+#if OSL_DEBUG_LEVEL >= 2
+ _numRegisteredObjects = 0;
+#endif
+}
+
+Cli_environment::~Cli_environment() ///< IDisposable Cli_environment::Dispose()
+{
+ this->!Cli_environment(); // call finalizer
+}
+
+Cli_environment::!Cli_environment() ///< Cli_environment::Finalize()
+{
+#if OSL_DEBUG_LEVEL >= 2
+ OSL_ENSURE(_numRegisteredObjects == 0,
+ "cli uno bridge: CLI environment contains unrevoked objects");
+#endif
+}
+
+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, gcnew 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, gcnew WeakReference(obj));
+ return obj;
+}
+
+void Cli_environment::revokeInterface(System::String^ oid, System::Type^ type)
+{
+ System::String^ key = type != nullptr ? 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(
+ gcnew System::String("cli uno bridge: {0} remaining registered interfaces"),
+ m_objects->Count - 1));
+#endif
+ m_objects->Remove(key);
+}
+
+inline void Cli_environment::revokeInterface(System::String^ oid)
+{
+ return revokeInterface(oid, nullptr);
+}
+
+System::Object^ Cli_environment::getRegisteredInterface(System::String^ oid,
+ System::Type^ type)
+{
+ //try if it is a UNO interface
+ System::Object^ ret = m_objects[oid];
+ if (! ret)
+ {
+ //try if it is a proxy for a cli object
+ oid = createKey(oid, type);
+ ret = m_objects[ oid ];
+ }
+ if (ret != nullptr)
+ {
+ System::WeakReference^ weakIface =
+ static_cast< System::WeakReference ^ >( ret );
+ ret = weakIface->Target;
+ }
+ if (ret == nullptr)
+ m_objects->Remove( oid );
+ return ret;
+}
+
+System::String^ Cli_environment::getObjectIdentifier(System::Object^ obj)
+{
+ System::String^ oId= nullptr;
+ RealProxy^ aProxy= RemotingServices::GetRealProxy(obj);
+ if (aProxy)
+ {
+ UnoInterfaceProxy^ proxyImpl= dynamic_cast<UnoInterfaceProxy^>(aProxy);
+ if (proxyImpl)
+ oId= proxyImpl->getOid();
+ }
+
+ if (oId == nullptr)
+ {
+ StringBuilder ^ buf= gcnew StringBuilder(256);
+ bool bFirst = new bool(false);
+ System::Threading::Monitor::Enter(Cli_environment::typeid);
+ try {
+ buf->Append(m_IDGen->GetId(obj, bFirst));
+ } finally
+ {
+ System::Threading::Monitor::Exit(Cli_environment::typeid);
+ }
+
+ buf->Append(sOidPart);
+ oId= buf->ToString();
+ }
+ return oId;
+}
+} //namespace cli_uno
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..3828d971c
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_environment.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_ENVIRONMENT_H
+#define INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_ENVIRONMENT_H
+
+#include "cli_base.h"
+
+using namespace System;
+using namespace System::Collections;
+using namespace System::Runtime::Serialization;
+
+namespace cli_uno
+{
+public
+ref 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
+
+ static Cli_environment()
+ {
+ m_objects = Hashtable::Synchronized(gcnew Hashtable());
+ m_IDGen = gcnew System::Runtime::Serialization::ObjectIDGenerator();
+ System::Text::StringBuilder ^ buffer = gcnew System::Text::StringBuilder(256);
+ Guid gd = Guid::NewGuid();
+ buffer->Append(";cli[0];");
+ buffer->Append(gd.ToString());
+ sOidPart = buffer->ToString();
+ }
+
+public:
+ inline Cli_environment();
+
+ ~Cli_environment();
+ !Cli_environment();
+
+ /**
+ Registers a 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 an Oid should be generated.
+ */
+ static System::String ^ getObjectIdentifier(Object ^ obj);
+};
+
+} //namespace cli_uno
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cli_ure/source/uno_bridge/cli_proxy.cxx b/cli_ure/source/uno_bridge/cli_proxy.cxx
new file mode 100644
index 000000000..22c478177
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_proxy.cxx
@@ -0,0 +1,1105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "typelib/typedescription.h"
+#include "rtl/ustrbuf.hxx"
+#include <sal/log.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include "cli_proxy.h"
+#include "cli_base.h"
+#include "cli_bridge.h"
+
+#using <cli_ure.dll>
+#using <cli_uretypes.dll>
+
+namespace sr = System::Reflection;
+namespace st = System::Text;
+namespace sc = System::Collections;
+namespace srrm = System::Runtime::Remoting::Messaging;
+namespace srr = System::Runtime::Remoting;
+namespace srrp = System::Runtime::Remoting::Proxies;
+namespace sd = System::Diagnostics;
+namespace ucss = unoidl::com::sun::star;
+
+using namespace cli_uno;
+
+extern "C"
+{
+
+void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy )
+ SAL_THROW_EXTERN_C();
+
+void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+void SAL_CALL cli_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C();
+
+
+}
+
+namespace cli_uno
+{
+
+UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
+ typelib_InterfaceTypeDescription* td):
+
+ m_unoI(unoI),
+ m_typeDesc(td),
+ m_bridge(bridge)
+{
+ m_bridge->acquire();
+ m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td));
+ m_unoI->acquire(m_unoI);
+ typelib_typedescription_acquire(&m_typeDesc->aBase);
+ if ( ! m_typeDesc->aBase.bComplete)
+ {
+ typelib_TypeDescription* _pt = &m_typeDesc->aBase;
+ sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
+ if( ! bComplete)
+ {
+ throw BridgeRuntimeError("cannot make type complete: " + OUString::unacquired(& m_typeDesc->aBase.pTypeName));
+ }
+ }
+}
+
+UnoInterfaceInfo::~UnoInterfaceInfo() ///< IDisposable UnoInterfaceInfo::Dispose()
+{
+ this->!UnoInterfaceInfo(); // call finalizer
+}
+
+UnoInterfaceInfo::!UnoInterfaceInfo() ///< UnoInterfaceInfo::Finalize()
+{
+ //accessing unmanaged objects is ok.
+ m_bridge->m_uno_env->revokeInterface(
+ m_bridge->m_uno_env, m_unoI );
+ m_bridge->release();
+
+ m_unoI->release(m_unoI);
+ typelib_typedescription_release(
+ reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
+}
+
+UnoInterfaceProxy::UnoInterfaceProxy(
+ Bridge * bridge,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription* pTD,
+ const OUString& oid )
+ :RealProxy(MarshalByRefObject::typeid),
+ m_bridge(bridge),
+ m_oid(mapUnoString(oid.pData)),
+ m_sTypeName(m_system_Object_String)
+{
+ m_bridge->acquire();
+ // create the list that holds all UnoInterfaceInfos
+ m_listIfaces = gcnew ArrayList(10);
+ m_numUnoIfaces = 0;
+ m_listAdditionalProxies = gcnew ArrayList();
+ m_nlistAdditionalProxies = 0;
+ //put the information of the first UNO interface into the arraylist
+#if OSL_DEBUG_LEVEL >= 2
+ _numInterfaces = 0;
+ _sInterfaces = NULL;
+#endif
+ addUnoInterface(pUnoI, pTD);
+
+}
+
+UnoInterfaceProxy::~UnoInterfaceProxy() ///< IDisposable UnoInterfaceProxy::Dispose()
+{
+ this->!UnoInterfaceProxy(); // call finalizer
+}
+
+UnoInterfaceProxy::!UnoInterfaceProxy() ///< UnoInterfaceProxy::Finalize()
+{
+#if OSL_DEBUG_LEVEL >= 2
+ sd::Trace::WriteLine(System::String::Format(
+ gcnew System::String("cli uno bridge: Destroying proxy "
+ "for UNO object, OID: \n\t{0} \n\twith uno interfaces: "),
+ m_oid));
+
+ sd::Trace::WriteLine( mapUnoString(_sInterfaces));
+ rtl_uString_release(_sInterfaces);
+#endif
+ //m_bridge is unmanaged, therefore we can access it in this finalizer
+ CliEnvHolder::g_cli_env->revokeInterface(m_oid);
+ m_bridge->release();
+}
+
+System::Object^ UnoInterfaceProxy::create(
+ Bridge * bridge,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription* pTD,
+ const OUString& oid)
+{
+ UnoInterfaceProxy^ proxyHandler=
+ gcnew UnoInterfaceProxy(bridge, pUnoI, pTD, oid);
+ System::Object^ proxy= proxyHandler->GetTransparentProxy();
+ CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData));
+ return proxy;
+}
+
+
+void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
+ typelib_InterfaceTypeDescription* pTd)
+{
+ sc::IEnumerator^ enumInfos = m_listIfaces->GetEnumerator();
+ System::Threading::Monitor::Enter(this);
+ try
+ {
+ while (enumInfos->MoveNext())
+ {
+ UnoInterfaceInfo^ info = static_cast<UnoInterfaceInfo^>(
+ enumInfos->Current);
+ if (typelib_typedescription_equals(
+ reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc),
+ reinterpret_cast<typelib_TypeDescription*>(pTd)))
+ {
+ return;
+ }
+ }
+ OUString oid(mapCliString(m_oid));
+ (*m_bridge->m_uno_env->registerInterface)(
+ m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
+ oid.pData, pTd);
+ //This proxy does not contain the uno_Interface. Add it.
+ m_listIfaces->Add(gcnew UnoInterfaceInfo(m_bridge, pUnoI, pTd));
+ m_numUnoIfaces = m_listIfaces->Count;
+#if OSL_DEBUG_LEVEL >= 2
+ System::String^ sInterfaceName = static_cast<UnoInterfaceInfo^>(
+ m_listIfaces[m_numUnoIfaces - 1])->m_type->FullName;
+ sd::Trace::WriteLine(System::String::Format(
+ gcnew System::String("cli uno bridge: Creating proxy for uno object, "
+ "id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName));
+ // add to the string that contains all interface names
+ _numInterfaces++;
+ OUString _sNewInterface = "\t" + OUString::number(_numInterfaces) + ". " + mapCliString(sInterfaceName) + "\n";
+ pin_ptr<rtl_uString *> pp_sInterfaces = &_sInterfaces;
+ rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces,
+ _sNewInterface.pData);
+#endif
+ }
+ __finally {
+ System::Threading::Monitor::Exit(this);
+ }
+}
+
+
+// IRemotingTypeInfo
+bool UnoInterfaceProxy::CanCastTo(System::Type^ fromType,
+ System::Object^)
+{
+ if (fromType == System::Object::typeid) // trivial case
+ return true;
+
+ System::Threading::Monitor::Enter(this);
+ try
+ {
+ if (nullptr != findInfo( fromType )) // proxy supports demanded interface
+ return true;
+
+ //query a uno interface for the required type
+
+ // we use the first interface in the list (m_listIfaces) to make
+ // the queryInterface call
+ UnoInterfaceInfo^ info =
+ static_cast<UnoInterfaceInfo^>(m_listIfaces[0]);
+ css::uno::TypeDescription membertd(
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(
+ info->m_typeDesc)->ppAllMembers[0]);
+ array<System::Object^>^ args = gcnew array<System::Object^>(1);
+
+ args[0] = fromType;
+ uno::Any ^ pAny;
+ System::Object^ pException = nullptr;
+
+ pAny= static_cast<uno::Any ^>(
+ m_bridge->call_uno(
+ info->m_unoI,
+ membertd.get(),
+ ((typelib_InterfaceMethodTypeDescription*)
+ membertd.get())->pReturnTypeRef,
+ 1,
+ ((typelib_InterfaceMethodTypeDescription*)
+ membertd.get())->pParams,
+ args, nullptr, &pException) );
+
+ // handle regular exception from target
+ OSL_ENSURE(
+ nullptr == pException,
+ OUStringToOString(
+ mapCliString( pException->ToString()),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ if (pAny->Type != void::typeid) // has value?
+ {
+ if (nullptr != findInfo( fromType ))
+ {
+ // proxy now supports demanded interface
+ return true;
+ }
+
+ // via aggregation: it is possible that queryInterface() returns
+ // and interface with a different oid.
+ // That way, this type is supported for the CLI
+ // interpreter (CanCastTo() returns true)
+ ::System::Object ^ obj = pAny->Value;
+ OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) );
+ if (srr::RemotingServices::IsTransparentProxy( obj ))
+ {
+ UnoInterfaceProxy ^ proxy =
+ static_cast< UnoInterfaceProxy ^ >(
+ srr::RemotingServices::GetRealProxy( obj ) );
+ OSL_ASSERT( nullptr != proxy->findInfo( fromType ) );
+ m_listAdditionalProxies->Add( proxy );
+ m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
+ OSL_ASSERT( nullptr != findInfo( fromType ) );
+ return true;
+ }
+ }
+ }
+ catch (BridgeRuntimeError& e)
+ {
+ (void) e; // avoid warning
+ OSL_FAIL(
+ OUStringToOString(
+ e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ catch (System::Exception^ e)
+ {
+ System::String^ msg= gcnew System::String(
+ "An unexpected CLI exception occurred in "
+ "UnoInterfaceProxy::CanCastTo(). Original"
+ "message: \n");
+ msg= System::String::Concat(msg, e->Message);
+ OSL_FAIL(
+ OUStringToOString(
+ mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ catch (...)
+ {
+ OSL_FAIL(
+ "An unexpected native C++ exception occurred in "
+ "UnoInterfaceProxy::CanCastTo()" );
+ }
+ __finally
+ {
+ System::Threading::Monitor::Exit(this);
+ }
+ return false;
+}
+
+srrm::IMessage^ UnoInterfaceProxy::invokeObject(
+ sc::IDictionary^ props,
+ srrm::LogicalCallContext^ context,
+ srrm::IMethodCallMessage^ mcm)
+{
+ System::Object^ retMethod = nullptr;
+ System::String^ sMethod = static_cast<System::String^>
+ (props[m_methodNameString]);
+ array<System::Object^>^ args = static_cast<array<System::Object^>^>(
+ props[m_ArgsString]);
+ if (m_Equals_String->Equals(sMethod))
+ {
+ // Object.Equals
+ OSL_ASSERT(args->Length == 1);
+ srrp::RealProxy^ rProxy = srr::RemotingServices::GetRealProxy(args[0]);
+ bool bDone = false;
+ if (rProxy)
+ {
+ UnoInterfaceProxy^ unoProxy =
+ dynamic_cast<UnoInterfaceProxy^>(rProxy);
+ if (unoProxy)
+ {
+ bool b = m_oid->Equals(unoProxy->getOid());
+ retMethod = b;
+ bDone = true;
+ }
+ }
+ if (bDone == false)
+ {
+ //no proxy or not our proxy, therefore Equals must be false
+ retMethod = false;
+ }
+ }
+ else if (m_GetHashCode_String->Equals(sMethod))
+ {
+ // Object.GetHashCode
+ int nHash = m_oid->GetHashCode();
+ retMethod = nHash;
+ }
+ else if (m_GetType_String->Equals(sMethod))
+ {
+ // Object.GetType
+ retMethod = System::Object::typeid;
+ }
+ else if (m_ToString_String->Equals(sMethod))
+ {
+ // Object.ToString
+ st::StringBuilder^ sb = gcnew st::StringBuilder(256);
+// sb->AppendFormat("Uno object proxy. Implemented interface: {0}"
+// ". OID: {1}", m_type->ToString(), m_oid);
+ sb->AppendFormat("Uno object proxy. OID: {0}", m_oid);
+ retMethod = sb->ToString();
+ }
+ else
+ {
+ //Either Object has new functions or a protected method was called
+ //which should not be possible
+ OSL_ASSERT(0);
+ }
+ srrm::IMessage^ retVal= gcnew srrm::ReturnMessage(
+ retMethod, gcnew array<System::Object^>(0), 0, context, mcm);
+ return retVal;
+}
+
+UnoInterfaceInfo ^ UnoInterfaceProxy::findInfo( ::System::Type ^ type )
+{
+ for (int i = 0; i < m_numUnoIfaces; i++)
+ {
+ UnoInterfaceInfo^ tmpInfo = static_cast<UnoInterfaceInfo^>(
+ m_listIfaces[i]);
+ if (type->IsAssignableFrom(tmpInfo->m_type))
+ return tmpInfo;
+ }
+ for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
+ {
+ UnoInterfaceProxy ^ proxy =
+ static_cast< UnoInterfaceProxy ^ >(
+ m_listAdditionalProxies[ i ] );
+ UnoInterfaceInfo ^ info = proxy->findInfo( type );
+ if (nullptr != info)
+ return info;
+ }
+ return nullptr;
+}
+
+srrm::IMessage^ UnoInterfaceProxy::Invoke(srrm::IMessage^ callmsg)
+{
+ try
+ {
+ sc::IDictionary^ props= callmsg->Properties;
+ srrm::LogicalCallContext^ context=
+ static_cast<srrm::LogicalCallContext^>(
+ props[m_CallContextString]);
+ srrm::IMethodCallMessage^ mcm=
+ static_cast<srrm::IMethodCallMessage^>(callmsg);
+
+ //Find out which UNO interface is being called
+ System::String^ sTypeName = static_cast<System::String^>(
+ props[m_typeNameString]);
+ sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(','));
+
+ // Special Handling for System.Object methods
+ if(sTypeName->IndexOf(m_system_Object_String) != -1)
+ {
+ return invokeObject(props, context, mcm);
+ }
+
+ System::Type^ typeBeingCalled = loadCliType(sTypeName);
+ UnoInterfaceInfo^ info = findInfo( typeBeingCalled );
+ OSL_ASSERT( nullptr != info );
+
+ // ToDo do without string conversion, an OUString is not needed here
+ // get the type description of the call
+ OUString usMethodName(mapCliString(static_cast<System::String^>(
+ props[m_methodNameString])));
+ typelib_TypeDescriptionReference ** ppAllMembers =
+ info->m_typeDesc->ppAllMembers;
+ sal_Int32 numberMembers = info->m_typeDesc->nAllMembers;
+ for ( sal_Int32 nPos = numberMembers; nPos--; )
+ {
+ typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
+
+ // check usMethodName against fully qualified usTypeName
+ // of member_type; usTypeName is of the form
+ // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>)
+ OUString const & usTypeName =
+ OUString::unacquired( & member_type->pTypeName );
+
+#if OSL_DEBUG_LEVEL >= 2
+ System::String^ pTypeName;
+ pTypeName = mapUnoString(usTypeName.pData);
+#endif
+ sal_Int32 offset = usTypeName.indexOf( ':' ) + 2;
+ OSL_ASSERT(
+ offset >= 2 && offset < usTypeName.getLength()
+ && usTypeName[offset - 1] == ':' );
+ sal_Int32 remainder = usTypeName.getLength() - offset;
+
+ if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
+ {
+ if ((usMethodName.getLength() == remainder
+ || (usMethodName.getLength() < remainder
+ && usTypeName[offset + usMethodName.getLength()] == ':'))
+ && usTypeName.match(usMethodName, offset))
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceMethodTypeDescription * method_td =
+ (typelib_InterfaceMethodTypeDescription *)
+ member_td.get();
+
+ array<System::Object^>^ args = static_cast<array<System::Object^>^>(
+ props[m_ArgsString]);
+ array<System::Type^>^ argTypes = static_cast<array<System::Type^>^>(
+ props[m_methodSignatureString]);
+ System::Object^ pExc = nullptr;
+ System::Object ^ cli_ret = m_bridge->call_uno(
+ info->m_unoI, member_td.get(),
+ method_td->pReturnTypeRef, method_td->nParams,
+ method_td->pParams, args, argTypes, &pExc);
+ return constructReturnMessage(cli_ret, args, method_td,
+ callmsg, pExc);
+ }
+ }
+ else
+ {
+ OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE ==
+ member_type->eTypeClass );
+ if (usMethodName.getLength() > 4
+ && (usMethodName.getLength() - 4 == remainder
+ || (usMethodName.getLength() - 4 < remainder
+ && usTypeName[
+ offset + (usMethodName.getLength() - 4)] == ':'))
+ && usMethodName[1] == 'e' && usMethodName[2] == 't'
+ && rtl_ustr_compare_WithLength(
+ usTypeName.getStr() + offset,
+ usMethodName.getLength() - 4,
+ usMethodName.getStr() + 4,
+ usMethodName.getLength() - 4) == 0)
+ {
+ if ('g' == usMethodName[0])
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attribute_td =
+ (typelib_InterfaceAttributeTypeDescription*)
+ member_td.get();
+
+ System::Object^ pExc = nullptr;
+ System::Object^ cli_ret= m_bridge->call_uno(
+ info->m_unoI, member_td.get(),
+ attribute_td->pAttributeTypeRef,
+ 0, 0,
+ nullptr, nullptr, &pExc);
+ return constructReturnMessage(cli_ret, nullptr, NULL,
+ callmsg, pExc);
+ }
+ else if ('s' == usMethodName[0])
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attribute_td =
+ (typelib_InterfaceAttributeTypeDescription *)
+ member_td.get();
+ if (! attribute_td->bReadOnly)
+ {
+ typelib_MethodParameter param;
+ param.pTypeRef = attribute_td->pAttributeTypeRef;
+ param.bIn = sal_True;
+ param.bOut = sal_False;
+
+ array<System::Object^>^ args =
+ static_cast<array<System::Object^>^>(
+ props[m_ArgsString]);
+ System::Object^ pExc = nullptr;
+ m_bridge->call_uno(
+ info->m_unoI, member_td.get(),
+ cppu::UnoType<void>::get().getTypeLibType(),
+ 1, &param, args, nullptr, &pExc);
+ return constructReturnMessage(nullptr, nullptr, NULL,
+ callmsg, pExc);
+ }
+ else
+ {
+ return constructReturnMessage(nullptr, nullptr, NULL,
+ callmsg, nullptr);
+ }
+ }
+ break;
+ }
+ }
+ }
+ // ToDo check if the message of the exception is not crippled
+ // the thing that should not be... no method info found!
+ throw BridgeRuntimeError("[cli_uno bridge]calling undeclared function on interface " +
+ OUString::unacquired(& ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName) +
+ ": " + usMethodName);
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ srrm::IMethodCallMessage^ mcm =
+ static_cast<srrm::IMethodCallMessage^>(callmsg);
+ return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
+ mapUnoString(err.m_message.pData), nullptr), mcm);
+ }
+ catch (System::Exception^ e)
+ {
+ st::StringBuilder ^ sb = gcnew st::StringBuilder(512);
+ sb->Append(gcnew System::String(
+ "An unexpected CLI exception occurred in "
+ "UnoInterfaceProxy::Invoke. Original"
+ "message: \n"));
+ sb->Append(e->Message);
+ sb->Append((__wchar_t) '\n');
+ sb->Append(e->StackTrace);
+ srrm::IMethodCallMessage^ mcm =
+ static_cast<srrm::IMethodCallMessage^>(callmsg);
+ return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
+ sb->ToString(), nullptr), mcm);
+ }
+ catch (...)
+ {
+ System::String^ msg = gcnew System::String(
+ "An unexpected native C++ exception occurred in "
+ "UnoInterfaceProxy::Invoke.");
+ srrm::IMethodCallMessage^ mcm =
+ static_cast<srrm::IMethodCallMessage^>(callmsg);
+ return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
+ msg, nullptr), mcm);
+ }
+ return nullptr;
+}
+/** If the argument args is NULL then this function is called for an attribute
+ method (either setXXX or getXXX).
+ For attributes the argument mtd is also NULL.
+*/
+srrm::IMessage^ UnoInterfaceProxy::constructReturnMessage(
+ System::Object^ cliReturn,
+ array<System::Object^>^ args,
+ typelib_InterfaceMethodTypeDescription* mtd,
+ srrm::IMessage^ msg, System::Object^ exc)
+{
+ srrm::IMessage ^ retVal= nullptr;
+ srrm::IMethodCallMessage^ mcm = static_cast<srrm::IMethodCallMessage^>(msg);
+ if (exc)
+ {
+ retVal = gcnew srrm::ReturnMessage(
+ dynamic_cast<System::Exception^>(exc), mcm);
+ }
+ else
+ {
+ sc::IDictionary^ props= msg->Properties;
+ srrm::LogicalCallContext^ context=
+ static_cast<srrm::LogicalCallContext^>(
+ props[m_CallContextString]);
+ if (args != nullptr)
+ {
+ // Method
+ //build the array of out parameters, allocate max length
+ array<System::Object^>^ arOut= gcnew array<System::Object^>(mtd->nParams);
+ int nOut = 0;
+ for (int i= 0; i < mtd->nParams; i++)
+ {
+ if (mtd->pParams[i].bOut)
+ {
+ arOut[i]= args[i];
+ nOut++;
+ }
+ }
+ retVal= gcnew srrm::ReturnMessage(cliReturn, arOut, nOut,
+ context, mcm);
+ }
+ else
+ {
+ // Attribute (getXXX)
+ retVal= gcnew srrm::ReturnMessage(cliReturn, nullptr, 0,
+ context, mcm);
+ }
+ }
+ return retVal;
+}
+
+
+CliProxy::CliProxy(Bridge const* bridge, System::Object^ cliI,
+ typelib_TypeDescription const* td,
+ const OUString& usOid):
+ m_ref(1),
+ m_bridge(bridge),
+ m_cliI(cliI),
+ m_unoType(const_cast<typelib_TypeDescription*>(td)),
+ m_usOid(usOid),
+ m_oid(mapUnoString(usOid.pData)),
+ m_nInheritedInterfaces(0)
+{
+ m_bridge->acquire();
+ uno_Interface::acquire = cli_proxy_acquire;
+ uno_Interface::release = cli_proxy_release;
+ uno_Interface::pDispatcher = cli_proxy_dispatch;
+
+ m_unoType.makeComplete();
+ m_type= mapUnoType(m_unoType.get());
+
+ makeMethodInfos();
+#if OSL_DEBUG_LEVEL >= 2
+ sd::Trace::WriteLine(System::String::Format(
+ gcnew System::String("cli uno bridge: Creating proxy for cli object, "
+ "id:\n\t{0}\n\t{1}"), m_oid, m_type));
+#endif
+
+}
+
+void CliProxy::makeMethodInfos()
+{
+#if OSL_DEBUG_LEVEL >= 2
+ System::Object^ cliI;
+ System::Type^ type;
+ cliI = m_cliI;
+ type = m_type;
+#endif
+
+ if (m_type->IsInterface == false)
+ return;
+ array<sr::MethodInfo^>^ arThisMethods = m_type->GetMethods();
+ //get the inherited interfaces
+ array<System::Type^>^ arInheritedIfaces = m_type->GetInterfaces();
+ m_nInheritedInterfaces = arInheritedIfaces->Length;
+ //array containing the number of methods for the interface and its
+ //inherited interfaces
+ m_arInterfaceMethodCount = gcnew array<int^>(m_nInheritedInterfaces + 1);
+ //determine the number of all interface methods, including the inherited
+ //interfaces
+ int numMethods = arThisMethods->Length;
+ for (int i= 0; i < m_nInheritedInterfaces; i++)
+ {
+ numMethods += arInheritedIfaces[i]->GetMethods()->Length;
+ }
+ //array containing MethodInfos of the cli object
+ m_arMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
+ //array containing MethodInfos of the interface
+ m_arInterfaceMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
+ //array containing the mapping of Uno interface pos to pos in
+ //m_arMethodInfos
+ m_arUnoPosToCliPos = gcnew array<System::Int32>(numMethods);
+ // initialize with -1
+ for (int i = 0; i < numMethods; i++)
+ m_arUnoPosToCliPos[i] = -1;
+
+ //fill m_arMethodInfos with the mappings
+ // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
+ // to documentation
+ // but it is Type*[] instead. Bug in the framework?
+ System::Type^ objType = m_cliI->GetType();
+ try
+ {
+ int index = 0;
+ // now get the methods from the inherited interface
+ //arInheritedIfaces[0] is the direct base interface
+ //arInheritedIfaces[n] is the furthest inherited interface
+ //Start with the base interface
+ int nArLength = arInheritedIfaces->Length;
+ for (;nArLength > 0; nArLength--)
+ {
+ sr::InterfaceMapping mapInherited = objType->GetInterfaceMap(
+ arInheritedIfaces[nArLength - 1]);
+ int numMethods = mapInherited.TargetMethods->Length;
+ m_arInterfaceMethodCount[nArLength - 1] = numMethods;
+ for (int i = 0; i < numMethods; i++, index++)
+ {
+ m_arMethodInfos[index] = safe_cast<sr::MethodInfo^>(
+ mapInherited.TargetMethods[i]);
+
+ m_arInterfaceMethodInfos[index] = safe_cast<sr::MethodInfo^>(
+ mapInherited.InterfaceMethods[i]);
+ }
+ }
+ //At last come the methods of the furthest derived interface
+ sr::InterfaceMapping map = objType->GetInterfaceMap(m_type);
+ nArLength = map.TargetMethods->Length;
+ m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength;
+ for (int i = 0; i < nArLength; i++,index++)
+ {
+ m_arMethodInfos[index]= safe_cast<sr::MethodInfo^>(
+ map.TargetMethods[i]);
+ m_arInterfaceMethodInfos[index]= safe_cast<sr::MethodInfo^>(
+ map.InterfaceMethods[i]);
+ }
+ }
+ catch (System::InvalidCastException^ )
+ {
+ throw BridgeRuntimeError("[cli_uno bridge] preparing proxy for cli interface: " + mapCliString(m_type->ToString()) + " \nfailed!");
+ }
+}
+
+sr::MethodInfo^ CliProxy::getMethodInfo(int nUnoFunctionPos,
+ const OUString& usMethodName, MethodKind methodKind)
+{
+ sr::MethodInfo^ ret = nullptr;
+ //deduct 3 for XInterface methods
+ nUnoFunctionPos -= 3;
+ System::Threading::Monitor::Enter(m_arUnoPosToCliPos);
+ try
+ {
+ int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos];
+ if (cliPos != -1)
+ return m_arMethodInfos[cliPos];
+
+ //create the method function name
+ System::String^ sMethodName = mapUnoString(usMethodName.pData);
+ switch (methodKind)
+ {
+ case MK_METHOD:
+ break;
+ case MK_SET:
+ sMethodName = System::String::Concat(
+ const_cast<System::String^>(Constants::sAttributeSet),
+ sMethodName);
+ break;
+ case MK_GET:
+ sMethodName = System::String::Concat(
+ const_cast<System::String^>(Constants::sAttributeGet),
+ sMethodName);
+ break;
+ default:
+ OSL_ASSERT(0);
+ }
+ //Find the cli interface method that corresponds to the Uno method
+// System::String* sMethodName= mapUnoString(usMethodName.pData);
+ int indexCliMethod = -1;
+ //If the cli interfaces and their methods are in the same order
+ //as they were declared (inheritance chain and within the interface)
+ //then nUnoFunctionPos should lead to the correct method. However,
+ //the documentation does not say that this ordering is given.
+ if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name))
+ indexCliMethod = nUnoFunctionPos;
+ else
+ {
+ int cMethods = m_arInterfaceMethodInfos->Length;
+ for (int i = 0; i < cMethods; i++)
+ {
+ System::String^ cliMethod = m_arInterfaceMethodInfos[i]->Name;
+ if (cliMethod->Equals(sMethodName))
+ {
+ indexCliMethod = i;
+ break;
+ }
+ }
+ }
+ if (indexCliMethod == -1)
+ {
+ throw BridgeRuntimeError("[cli_uno bridge] CliProxy::getMethodInfo():cli object does not implement interface method: " + usMethodName);
+ }
+ m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
+ ret = m_arMethodInfos[indexCliMethod];
+ }
+ __finally
+ {
+ System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
+ }
+
+ return ret;
+}
+
+CliProxy::~CliProxy()
+{
+#if OSL_DEBUG_LEVEL >= 2
+ sd::Trace::WriteLine(System::String::Format(
+ gcnew System::String(
+ "cli uno bridge: Destroying proxy for cli object, "
+ "id:\n\t{0}\n\t{1}\n"),
+ m_oid, m_type));
+#endif
+ CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get()));
+ m_bridge->release();
+}
+
+uno_Interface* CliProxy::create(Bridge const * bridge,
+ System::Object^ cliI,
+ typelib_TypeDescription const* pTD,
+ const OUString& ousOid)
+{
+ uno_Interface* proxy= static_cast<uno_Interface*>(
+ new CliProxy(bridge, cliI, pTD, ousOid));
+
+ //register proxy with target environment (uno)
+ (*bridge->m_uno_env->registerProxyInterface)(
+ bridge->m_uno_env,
+ reinterpret_cast<void**>(&proxy),
+ cli_proxy_free,
+ ousOid.pData, (typelib_InterfaceTypeDescription*) pTD);
+ //register original interface
+ CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData),
+ mapUnoType((pTD)));
+
+ return proxy;
+}
+
+
+void SAL_CALL CliProxy::uno_DispatchMethod(
+ struct _uno_Interface *,
+ const struct _typelib_TypeDescription *,
+ void *,
+ void **,
+ uno_Any ** )
+{
+}
+inline void CliProxy::acquire() const
+{
+ if (1 == osl_atomic_increment( &m_ref ))
+ {
+ // rebirth of proxy zombie
+ void * that = const_cast< CliProxy * >( this );
+ // register at uno env
+ (*m_bridge->m_uno_env->registerProxyInterface)(
+ m_bridge->m_uno_env, &that,
+ cli_proxy_free, m_usOid.pData,
+ (typelib_InterfaceTypeDescription *)m_unoType.get() );
+#if OSL_DEBUG_LEVEL >= 2
+ OSL_ASSERT( this == (void const * const)that );
+#endif
+ }
+}
+
+inline void CliProxy::release() const
+{
+ if (0 == osl_atomic_decrement( &m_ref ))
+ {
+ // revoke from uno env on last release,
+ // The proxy can be resurrected if acquire is called before the uno
+ // environment calls cli_proxy_free. cli_proxy_free will
+ //delete the proxy. The environment does not acquire a registered
+ //proxy.
+ (*m_bridge->m_uno_env->revokeInterface)(
+ m_bridge->m_uno_env, const_cast< CliProxy * >( this ) );
+ }
+}
+}
+
+
+extern "C"
+void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
+ SAL_THROW_EXTERN_C()
+{
+ cli_uno::CliProxy * cliProxy = reinterpret_cast<
+ cli_uno::CliProxy * >( proxy );
+
+ delete cliProxy;
+}
+
+extern "C"
+void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
+ cliProxy->acquire();
+}
+
+extern "C"
+void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
+ cliProxy->release();
+}
+
+
+extern "C"
+
+void SAL_CALL cli_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C()
+{
+ CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
+ try
+ {
+ Bridge const* bridge = proxy->m_bridge;
+
+ switch (member_td->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
+ member_td)->nPosition;
+ typelib_InterfaceTypeDescription * iface_td =
+ (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
+ OSL_ENSURE(
+ member_pos < iface_td->nAllMembers,
+ "### member pos out of range!" );
+ sal_Int32 function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
+ OSL_ENSURE(
+ function_pos < iface_td->nMapFunctionIndexToMemberIndex,
+ "### illegal function index!" );
+
+ if (uno_ret) // is getter method
+ {
+ OUString const& usAttrName= *(rtl_uString**)&
+ ((typelib_InterfaceMemberTypeDescription*) member_td)
+ ->pMemberName;
+ sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
+ usAttrName, CliProxy::MK_GET);
+ bridge->call_cli(
+ proxy->m_cliI,
+ info,
+ ((typelib_InterfaceAttributeTypeDescription *)member_td)
+ ->pAttributeTypeRef,
+ 0, 0, // no params
+ uno_ret, 0, uno_exc );
+ }
+ else // is setter method
+ {
+ OUString const& usAttrName= *(rtl_uString**) &
+ ((typelib_InterfaceMemberTypeDescription*) member_td)
+ ->pMemberName;
+ sr::MethodInfo^ info = proxy->getMethodInfo(function_pos + 1,
+ usAttrName, CliProxy::MK_SET);
+ typelib_MethodParameter param;
+ param.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)member_td)
+ ->pAttributeTypeRef;
+ param.bIn = sal_True;
+ param.bOut = sal_False;
+
+ bridge->call_cli(
+ proxy->m_cliI,
+ // set follows get method
+ info,
+ 0 /* indicates void return */, &param, 1,
+ 0, uno_args, uno_exc );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
+ member_td)->nPosition;
+ typelib_InterfaceTypeDescription * iface_td =
+ (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
+ OSL_ENSURE(
+ member_pos < iface_td->nAllMembers,
+ "### member pos out of range!" );
+ sal_Int32 function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
+ OSL_ENSURE(
+ function_pos < iface_td->nMapFunctionIndexToMemberIndex,
+ "### illegal function index!" );
+
+ switch (function_pos)
+ {
+ case 0: // queryInterface()
+ {
+ TypeDescr demanded_td(
+ *reinterpret_cast<typelib_TypeDescriptionReference **>(
+ uno_args[0]));
+ if (typelib_TypeClass_INTERFACE
+ != demanded_td.get()->eTypeClass)
+ {
+ throw BridgeRuntimeError(
+ "queryInterface() call demands an INTERFACE type!");
+ }
+
+ uno_Interface * pInterface = 0;
+ (*bridge->m_uno_env->getRegisteredInterface)(
+ bridge->m_uno_env,
+ (void **)&pInterface, proxy->m_usOid.pData,
+ (typelib_InterfaceTypeDescription *)demanded_td.get() );
+
+ if (0 == pInterface)
+ {
+ System::Type^ mgdDemandedType =
+ mapUnoType(demanded_td.get());
+ if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
+ {
+#if OSL_DEBUG_LEVEL > 0
+ OUString usOid(
+ mapCliString(
+ CliEnvHolder::g_cli_env->getObjectIdentifier(
+ proxy->m_cliI )));
+ OSL_ENSURE(usOid.equals( proxy->m_usOid ),
+ "### different oids!");
+#endif
+ uno_Interface* pUnoI = bridge->map_cli2uno(
+ proxy->m_cliI, demanded_td.get() );
+ uno_any_construct(
+ (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 );
+ (*pUnoI->release)( pUnoI );
+ }
+ else // object does not support demanded interface
+ {
+ uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
+ }
+ // no exception occurred
+ *uno_exc = 0;
+ }
+ else
+ {
+ uno_any_construct(
+ reinterpret_cast< uno_Any * >( uno_ret ),
+ &pInterface, demanded_td.get(), 0 );
+ (*pInterface->release)( pInterface );
+ *uno_exc = 0;
+ }
+ break;
+ }
+ case 1: // acquire this proxy
+ cli_proxy_acquire(proxy);
+ *uno_exc = 0;
+ break;
+ case 2: // release this proxy
+ cli_proxy_release(proxy);
+ *uno_exc = 0;
+ break;
+ default: // arbitrary method call
+ {
+ typelib_InterfaceMethodTypeDescription * method_td =
+ (typelib_InterfaceMethodTypeDescription *)member_td;
+ OUString const& usMethodName= *(rtl_uString**) &
+ ((typelib_InterfaceMemberTypeDescription*) member_td)
+ ->pMemberName;
+
+ sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
+ usMethodName, CliProxy::MK_METHOD);
+ bridge->call_cli(
+ proxy->m_cliI,
+ info,
+ method_td->pReturnTypeRef, method_td->pParams,
+ method_td->nParams,
+ uno_ret, uno_args, uno_exc);
+ return;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "illegal member type description!" );
+ }
+ }
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ // binary identical struct
+ css::uno::RuntimeException exc(
+ "[cli_uno bridge error] " + err.m_message,
+ css::uno::Reference<
+ css::uno::XInterface >() );
+ css::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
+ uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0);
+ SAL_WARN( "cli", exc);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..25f7d2801
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_proxy.h
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_PROXY_H
+#define INCLUDED_CLI_URE_SOURCE_UNO_BRIDGE_CLI_PROXY_H
+
+#include "uno/environment.hxx"
+#include "uno/mapping.hxx"
+#include "uno/dispatcher.h"
+#include "cli_bridge.h"
+#include "cli_environment.h"
+
+#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 ref class UnoInterfaceInfo
+{
+public:
+ UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
+ typelib_InterfaceTypeDescription* td);
+ ~UnoInterfaceInfo();
+ !UnoInterfaceInfo();
+
+ uno_Interface * m_unoI; // wrapped interface
+ System::Type ^ m_type;
+ typelib_InterfaceTypeDescription* m_typeDesc;
+
+ Bridge const* m_bridge;
+};
+
+public ref 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 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 OUString& oid);
+
+ /** RealProxy::Invoke */
+ virtual srrm::IMessage^ Invoke(srrm::IMessage^ msg) override;
+
+ /** 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();
+ !UnoInterfaceProxy();
+
+ inline System::String ^ getOid()
+ { return m_oid; }
+
+ //IRemotingTypeInfo ----------------------------------------------
+ virtual bool CanCastTo(System::Type^ fromType, System::Object^ o);
+
+ virtual property System::String^ TypeName
+ {
+ System::String^ get()
+ {
+ return m_sTypeName;
+ };
+ void set(System::String^ name)
+ {
+ m_sTypeName = name;
+ };
+ }
+
+
+private:
+ UnoInterfaceProxy(
+ Bridge * bridge,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription* pTD,
+ const OUString& oid );
+
+ static srrm::IMessage^ constructReturnMessage(System::Object^ retVal,
+ array<System::Object^>^ outArgs,
+ typelib_InterfaceMethodTypeDescription* mtd,
+ srrm::IMessage^ msg, System::Object^ exc);
+
+ static System::String^ m_methodNameString =
+ gcnew System::String("__MethodName");
+ static System::String^ m_typeNameString = gcnew System::String("__TypeName");
+ static System::String^ m_ArgsString = gcnew System::String("__Args");
+ static System::String^ m_CallContextString =
+ gcnew System::String("__CallContext");
+ static System::String^ m_system_Object_String =
+ gcnew System::String("System.Object");
+ static System::String^ m_methodSignatureString =
+ gcnew System::String("__MethodSignature");
+ static System::String^ m_Equals_String = gcnew System::String("Equals");
+ static System::String^ m_GetHashCode_String =
+ gcnew System::String("GetHashCode");
+ static System::String^ m_GetType_String = gcnew System::String("GetType");
+ static System::String^ m_ToString_String = gcnew 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 css::uno::TypeDescription m_unoType;
+ const gcroot<System::String^> m_oid;
+ const 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 because, the cli interface does not contain the XInterface
+ methods.
+ */
+ gcroot<array<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<array<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<array<System::Int32>^> m_arUnoPosToCliPos;
+
+ /** Count of inherited interfaces of the cli interface.
+ */
+ int m_nInheritedInterfaces;
+ /** Contains the number of methods of each interface.
+ */
+ gcroot<array<System::Int32^>^> m_arInterfaceMethodCount;
+
+ CliProxy( Bridge const* bridge, System::Object^ cliI,
+ typelib_TypeDescription const* pTD,
+ const OUString& usOid);
+ ~CliProxy();
+
+ static uno_Interface* create(Bridge const * bridge,
+ System::Object^ cliI,
+ typelib_TypeDescription const * TD,
+ 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 than one interface in its inheritance chain,
+ that is Type.GetInterfaces return more than one Type, then the mapping
+ table is partially initialized. 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 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 000000000..6af17e065
--- /dev/null
+++ b/cli_ure/source/uno_bridge/cli_uno.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/alloca.h>
+#include <osl/diagnose.h>
+#include "rtl/ustrbuf.hxx"
+#include "cli_base.h"
+#include "cli_bridge.h"
+
+namespace sr=System::Reflection;
+
+
+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,
+ array<System::Object^>^ args, array<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 value
+ //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->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
+ {
+ pin_ptr<System::Object^> ptr = &args[nPos];
+ map_to_cli(
+ ptr, uno_args[nPos], param.pTypeRef,
+ argTypes != nullptr ? argTypes[nPos] : nullptr, 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, nullptr, false);
+ uno_type_destructData(uno_ret, return_type, 0);
+ return cli_ret;
+ }
+ catch (...)
+ {
+ uno_type_destructData(uno_ret, return_type, 0);
+ throw;
+ }
+ }
+ return nullptr; // void return
+ }
+ else // exception occurred
+ {
+ // 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, nullptr, false);
+ return nullptr;
+ }
+}
+
+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
+{
+ array<System::Object^>^ args= gcnew array<System::Object^>(nParams);
+ for (int nPos= 0; nPos < nParams; nPos++)
+ {
+ typelib_MethodParameter const & param= params[nPos];
+ if (param.bIn)
+ {
+ pin_ptr<System::Object^> ptr = &args[nPos];
+ map_to_cli( ptr,
+ uno_args[nPos], param.pTypeRef, nullptr, false);
+ }
+ }
+ System::Object^ retInvoke= nullptr;
+ try
+ {
+ retInvoke= method->Invoke(cliI, args);
+ }
+ catch (sr::TargetInvocationException^ e)
+ {
+ System::Exception^ exc= e->InnerException;
+ css::uno::TypeDescription td(mapCliType(exc->GetType()));
+ // memory for exception
+ std::unique_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)
+ {
+ throw BridgeRuntimeError("Unexpected exception during invocation of cli object. Original message is: \n" + mapCliString(e->Message));
+ }
+
+ //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 occurred
+ *uno_exc = 0;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */