blob: 1e0d31fd67c34b077d7092aa3d2b49b0cbf9e184 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_cli_ure.hxx"
#include <vcclr.h>
//ToDo: remove when build with .NET 2
#pragma warning(push, 1)
#include <windows.h>
#include "uno/environment.hxx"
#pragma warning(pop)
#include "rtl/unload.h"
#include "uno/lbnames.h"
#include "uno/mapping.hxx"
#include "typelib/typedescription.hxx"
#include "rtl/ustring.hxx"
#include "cli_bridge.h"
#include "cli_proxy.h"
namespace srr= System::Runtime::Remoting;
namespace srrp= System::Runtime::Remoting::Proxies;
#using <mscorlib.dll>
#if defined(_MSC_VER) && (_MSC_VER < 1400)
#include <_vcclrit.h>
#endif
namespace cssu= com::sun::star::uno;
namespace sri= System::Runtime::InteropServices;
using namespace rtl;
namespace cli_uno
{
extern "C"
{
void SAL_CALL Mapping_acquire( uno_Mapping * mapping )
SAL_THROW_EXTERN_C()
{
Mapping const * that = static_cast< Mapping const * >( mapping );
that->m_bridge->acquire();
}
//--------------------------------------------------------------------------------------------------
void SAL_CALL Mapping_release( uno_Mapping * mapping )
SAL_THROW_EXTERN_C()
{
Mapping const * that = static_cast< Mapping const * >( mapping );
that->m_bridge->release();
}
//--------------------------------------------------------------------------------------------------
void SAL_CALL Mapping_cli2uno(
uno_Mapping * mapping, void ** ppOut,
void * pIn, typelib_InterfaceTypeDescription * td )
SAL_THROW_EXTERN_C()
{
uno_Interface ** ppUnoI = (uno_Interface **)ppOut;
intptr_t cliI = (intptr_t)pIn;
OSL_ENSURE( ppUnoI && td, "### null ptr!" );
if (0 != *ppUnoI)
{
uno_Interface * pUnoI = *(uno_Interface **)ppUnoI;
(*pUnoI->release)( pUnoI );
*ppUnoI = 0;
}
try
{
Mapping const * that = static_cast< Mapping const * >( mapping );
Bridge * bridge = that->m_bridge;
if (0 != cliI)
{
System::Object* cliObj= sri::GCHandle::op_Explicit(cliI).Target;
(*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td);
}
}
catch (BridgeRuntimeError & err)
{
#if OSL_DEBUG_LEVEL >= 1
OString cstr_msg(
OUStringToOString(
OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
OSL_ENSURE( 0, cstr_msg.getStr() );
#else
(void) err; // unused
#endif
}
}
//--------------------------------------------------------------------------------------------------
void SAL_CALL Mapping_uno2cli(
uno_Mapping * mapping, void ** ppOut,
void * pIn, typelib_InterfaceTypeDescription * td )
SAL_THROW_EXTERN_C()
{
try
{
OSL_ENSURE( td && ppOut, "### null ptr!" );
OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode))
&& (sizeof(System::Boolean) == sizeof(sal_Bool))
&& (sizeof(System::SByte) == sizeof(sal_Int8))
&& (sizeof(System::Int16) == sizeof(sal_Int16))
&& (sizeof(System::UInt16) == sizeof(sal_uInt16))
&& (sizeof(System::Int32) == sizeof(sal_Int32))
&& (sizeof(System::UInt32) == sizeof(sal_uInt32))
&& (sizeof(System::Int64) == sizeof(sal_Int64))
&& (sizeof(System::UInt64) == sizeof(sal_uInt64))
&& (sizeof(System::Single) == sizeof(float))
&& (sizeof(System::Double) == sizeof(double)),
"[cli_uno bridge] incompatible .NET data types");
intptr_t * ppDNetI = (intptr_t *)ppOut;
uno_Interface * pUnoI = (uno_Interface *)pIn;
Mapping const * that = static_cast< Mapping const * >( mapping );
Bridge * bridge = that->m_bridge;
if (0 != *ppDNetI)
{
sri::GCHandle::op_Explicit(ppDNetI).Free();
}
if (0 != pUnoI)
{
System::Object* cliI= bridge->map_uno2cli(pUnoI, td);
intptr_t ptr= NULL;
if(cliI)
{
ptr= sri::GCHandle::op_Explicit(sri::GCHandle::Alloc(cliI))
#ifdef _WIN32
.ToInt32();
#else /* defined(_WIN64) */ .ToInt64();
#endif
}
(*ppOut)= reinterpret_cast<void*>(ptr);
}
}
catch (BridgeRuntimeError & err)
{
#if OSL_DEBUG_LEVEL >= 1
rtl::OString cstr_msg(
rtl::OUStringToOString(
OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
OSL_ENSURE( 0, cstr_msg.getStr() );
#else
(void) err; // unused
#endif
}
}
//__________________________________________________________________________________________________
void SAL_CALL Bridge_free( uno_Mapping * mapping )
SAL_THROW_EXTERN_C()
{
Mapping * that = static_cast< Mapping * >( mapping );
delete that->m_bridge;
}
} //extern C
} //namespace
namespace cli_uno
{
//__________________________________________________________________________________________________
/** ToDo
I doubt that the the case that the ref count raises from 0 to 1
can occur. uno_ext_getMapping returns an acquired mapping. Every time
that function is called then a new mapping is created. Following the
rules of ref counted objects, then if the ref count is null noone has
a reference to the object anymore. Hence noone can call acquire. If someone
calls acquire then they must have kept an unacquired pointer which is
illegal.
*/
void Bridge::acquire() const SAL_THROW( () )
{
if (1 == osl_incrementInterlockedCount( &m_ref ))
{
if (m_registered_cli2uno)
{
uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno);
uno_registerMapping(
& const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 );
}
else
{
uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli);
uno_registerMapping(
&mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 );
}
}
}
//__________________________________________________________________________________________________
void Bridge::release() const SAL_THROW( () )
{
if (! osl_decrementInterlockedCount( &m_ref ))
{
uno_revokeMapping(
m_registered_cli2uno
? const_cast<Mapping*>(&m_cli2uno)
: const_cast<Mapping*>(&m_uno2cli) );
}
}
//__________________________________________________________________________________________________
Bridge::Bridge(
uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env,
bool registered_cli2uno )
: m_ref( 1 ),
m_uno_env( uno_env ),
m_uno_cli_env( uno_cli_env ),
m_registered_cli2uno( registered_cli2uno )
{
OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env );
(*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env );
(*m_uno_cli_env->acquire)( m_uno_cli_env );
// cli2uno
m_cli2uno.acquire = Mapping_acquire;
m_cli2uno.release = Mapping_release;
m_cli2uno.mapInterface = Mapping_cli2uno;
m_cli2uno.m_bridge = this;
// uno2cli
m_uno2cli.acquire = Mapping_acquire;
m_uno2cli.release = Mapping_release;
m_uno2cli.mapInterface = Mapping_uno2cli;
m_uno2cli.m_bridge = this;
}
//__________________________________________________________________________________________________
Bridge::~Bridge() SAL_THROW( () )
{
//System::GC::Collect();
(*m_uno_cli_env->release)( m_uno_cli_env );
(*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env );
}
} //namespace cli_uno
extern "C"
{
namespace cli_uno
{
//--------------------------------------------------------------------------------------------------
void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env )
SAL_THROW_EXTERN_C()
{
uno_cli_env->pContext = 0;
}
//##################################################################################################
void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env )
SAL_THROW_EXTERN_C()
{
//ToDo: remove when compiled with .NET 2
#if defined(_MSC_VER) && (_MSC_VER < 1400)
__crt_dll_initialize();
#endif
uno_cli_env->environmentDisposing= cli_env_disposing;
uno_cli_env->pExtEnv = 0;
//Set the console to print Trace messages
#if OSL_DEBUG_LEVEL >= 1
System::Diagnostics::Trace::get_Listeners()->
Add( new System::Diagnostics::TextWriterTraceListener(System::Console::get_Out()));
#endif
OSL_ASSERT( 0 == uno_cli_env->pContext );
// We let the Cli_environment leak, since there is no good point where we could destruct it.
//dispose is not used because we would have then also synchronize the calls to proxies. If the
//Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points
//where g_cli_env is accessed.
//When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot
//member in a unmanaged class, such as Bridge.
CliEnvHolder::g_cli_env = new Cli_environment();
}
//##################################################################################################
void SAL_CALL uno_ext_getMapping(
uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
SAL_THROW_EXTERN_C()
{
OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo );
if (*ppMapping)
{
(*(*ppMapping)->release)( *ppMapping );
*ppMapping = 0;
}
OUString const & from_env_typename = *reinterpret_cast< OUString const * >(
&pFrom->pTypeName );
OUString const & to_env_typename = *reinterpret_cast< OUString const * >(
&pTo->pTypeName );
uno_Mapping * mapping = 0;
try
{
if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ) &&
to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ))
{
Bridge * bridge = new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
mapping = &bridge->m_cli2uno;
uno_registerMapping(
&mapping, Bridge_free, pFrom, (uno_Environment *)pTo->pExtEnv, 0 );
}
else if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) &&
to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ))
{
Bridge * bridge = new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
mapping = &bridge->m_uno2cli;
uno_registerMapping(
&mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 );
}
}
catch (BridgeRuntimeError & err)
{
#if OSL_DEBUG_LEVEL >= 1
OString cstr_msg(
OUStringToOString(
OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) );
OSL_ENSURE( 0, cstr_msg.getStr() );
#else
(void) err; // unused
#endif
}
*ppMapping = mapping;
}
//##################################################################################################
sal_Bool SAL_CALL component_canUnload( TimeValue * )
SAL_THROW_EXTERN_C()
{
return true;
}
}
}