1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_cli_ure.hxx" 26 27 #include <vcclr.h> 28 //ToDo: remove when build with .NET 2 29 #pragma warning(push, 1) 30 #include <windows.h> 31 #include "uno/environment.hxx" 32 #pragma warning(pop) 33 #include "rtl/unload.h" 34 #include "uno/lbnames.h" 35 #include "uno/mapping.hxx" 36 #include "typelib/typedescription.hxx" 37 #include "rtl/ustring.hxx" 38 39 #include "cli_bridge.h" 40 #include "cli_proxy.h" 41 namespace srr= System::Runtime::Remoting; 42 namespace srrp= System::Runtime::Remoting::Proxies; 43 #using <mscorlib.dll> 44 #if defined(_MSC_VER) && (_MSC_VER < 1400) 45 #include <_vcclrit.h> 46 #endif 47 48 namespace cssu= com::sun::star::uno; 49 50 51 namespace sri= System::Runtime::InteropServices; 52 using namespace rtl; 53 54 namespace cli_uno 55 { 56 57 extern "C" 58 { 59 void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) 60 SAL_THROW_EXTERN_C() 61 { 62 Mapping const * that = static_cast< Mapping const * >( mapping ); 63 that->m_bridge->acquire(); 64 } 65 //-------------------------------------------------------------------------------------------------- 66 void SAL_CALL Mapping_release( uno_Mapping * mapping ) 67 SAL_THROW_EXTERN_C() 68 { 69 Mapping const * that = static_cast< Mapping const * >( mapping ); 70 that->m_bridge->release(); 71 } 72 73 74 //-------------------------------------------------------------------------------------------------- 75 void SAL_CALL Mapping_cli2uno( 76 uno_Mapping * mapping, void ** ppOut, 77 void * pIn, typelib_InterfaceTypeDescription * td ) 78 SAL_THROW_EXTERN_C() 79 { 80 uno_Interface ** ppUnoI = (uno_Interface **)ppOut; 81 intptr_t cliI = (intptr_t)pIn; 82 83 OSL_ENSURE( ppUnoI && td, "### null ptr!" ); 84 85 if (0 != *ppUnoI) 86 { 87 uno_Interface * pUnoI = *(uno_Interface **)ppUnoI; 88 (*pUnoI->release)( pUnoI ); 89 *ppUnoI = 0; 90 } 91 try 92 { 93 Mapping const * that = static_cast< Mapping const * >( mapping ); 94 Bridge * bridge = that->m_bridge; 95 96 if (0 != cliI) 97 { 98 System::Object ^ cliObj= sri::GCHandle::FromIntPtr(System::IntPtr(cliI)).Target; 99 (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td); 100 } 101 } 102 catch (BridgeRuntimeError & err) 103 { 104 #if OSL_DEBUG_LEVEL >= 1 105 OString cstr_msg( 106 OUStringToOString( 107 OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); 108 OSL_ENSURE( 0, cstr_msg.getStr() ); 109 #else 110 (void) err; // unused 111 #endif 112 } 113 } 114 //-------------------------------------------------------------------------------------------------- 115 void SAL_CALL Mapping_uno2cli( 116 uno_Mapping * mapping, void ** ppOut, 117 void * pIn, typelib_InterfaceTypeDescription * td ) 118 SAL_THROW_EXTERN_C() 119 { 120 try 121 { 122 OSL_ENSURE( td && ppOut, "### null ptr!" ); 123 OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode)) 124 && (sizeof(System::Boolean) == sizeof(sal_Bool)) 125 && (sizeof(System::SByte) == sizeof(sal_Int8)) 126 && (sizeof(System::Int16) == sizeof(sal_Int16)) 127 && (sizeof(System::UInt16) == sizeof(sal_uInt16)) 128 && (sizeof(System::Int32) == sizeof(sal_Int32)) 129 && (sizeof(System::UInt32) == sizeof(sal_uInt32)) 130 && (sizeof(System::Int64) == sizeof(sal_Int64)) 131 && (sizeof(System::UInt64) == sizeof(sal_uInt64)) 132 && (sizeof(System::Single) == sizeof(float)) 133 && (sizeof(System::Double) == sizeof(double)), 134 "[cli_uno bridge] incompatible .NET data types"); 135 intptr_t * ppDNetI = (intptr_t *)ppOut; 136 uno_Interface * pUnoI = (uno_Interface *)pIn; 137 138 Mapping const * that = static_cast< Mapping const * >( mapping ); 139 Bridge * bridge = that->m_bridge; 140 141 if (0 != *ppDNetI) 142 { 143 // op_Explicit was MC++'s spelling of the conversion operator; 144 // C++/CLI names it FromIntPtr. Kept faithful to the original, 145 // which converts the POINTER and not *ppDNetI -- see the guard 146 // just above. That looks wrong, but changing it is a 147 // behavioural fix and does not belong in a syntax port. 148 sri::GCHandle::FromIntPtr(System::IntPtr(ppDNetI)).Free(); 149 } 150 151 if (0 != pUnoI) 152 { 153 System::Object ^ cliI= bridge->map_uno2cli(pUnoI, td); 154 intptr_t ptr= NULL; 155 if(cliI) 156 { 157 ptr= sri::GCHandle::ToIntPtr(sri::GCHandle::Alloc(cliI)) 158 #ifdef _WIN32 159 .ToInt32(); 160 #else /* defined(_WIN64) */ .ToInt64(); 161 #endif 162 } 163 (*ppOut)= reinterpret_cast<void*>(ptr); 164 } 165 } 166 catch (BridgeRuntimeError & err) 167 { 168 #if OSL_DEBUG_LEVEL >= 1 169 rtl::OString cstr_msg( 170 rtl::OUStringToOString( 171 OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); 172 OSL_ENSURE( 0, cstr_msg.getStr() ); 173 #else 174 (void) err; // unused 175 #endif 176 } 177 } 178 179 //__________________________________________________________________________________________________ 180 void SAL_CALL Bridge_free( uno_Mapping * mapping ) 181 SAL_THROW_EXTERN_C() 182 { 183 Mapping * that = static_cast< Mapping * >( mapping ); 184 delete that->m_bridge; 185 } 186 187 } //extern C 188 } //namespace 189 190 namespace cli_uno 191 { 192 193 //__________________________________________________________________________________________________ 194 /** ToDo 195 I doubt that the case that the ref count raises from 0 to 1 196 can occur. uno_ext_getMapping returns an acquired mapping. Every time 197 that function is called then a new mapping is created. Following the 198 rules of ref counted objects, then if the ref count is null no one has 199 a reference to the object anymore. Hence no one can call acquire. If someone 200 calls acquire then they must have kept an unacquired pointer which is 201 illegal. 202 */ 203 void Bridge::acquire() const SAL_THROW( () ) 204 { 205 if (1 == osl_incrementInterlockedCount( &m_ref )) 206 { 207 if (m_registered_cli2uno) 208 { 209 uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno); 210 uno_registerMapping( 211 & const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 ); 212 } 213 else 214 { 215 uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli); 216 uno_registerMapping( 217 &mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 ); 218 } 219 } 220 } 221 //__________________________________________________________________________________________________ 222 void Bridge::release() const SAL_THROW( () ) 223 { 224 if (! osl_decrementInterlockedCount( &m_ref )) 225 { 226 uno_revokeMapping( 227 m_registered_cli2uno 228 ? const_cast<Mapping*>(&m_cli2uno) 229 : const_cast<Mapping*>(&m_uno2cli) ); 230 } 231 } 232 //__________________________________________________________________________________________________ 233 Bridge::Bridge( 234 uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env, 235 bool registered_cli2uno ) 236 : m_ref( 1 ), 237 m_uno_env( uno_env ), 238 m_uno_cli_env( uno_cli_env ), 239 m_registered_cli2uno( registered_cli2uno ) 240 { 241 OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env ); 242 (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); 243 (*m_uno_cli_env->acquire)( m_uno_cli_env ); 244 245 // cli2uno 246 m_cli2uno.acquire = Mapping_acquire; 247 m_cli2uno.release = Mapping_release; 248 m_cli2uno.mapInterface = Mapping_cli2uno; 249 m_cli2uno.m_bridge = this; 250 // uno2cli 251 m_uno2cli.acquire = Mapping_acquire; 252 m_uno2cli.release = Mapping_release; 253 m_uno2cli.mapInterface = Mapping_uno2cli; 254 m_uno2cli.m_bridge = this; 255 256 } 257 258 //__________________________________________________________________________________________________ 259 Bridge::~Bridge() SAL_THROW( () ) 260 { 261 //System::GC::Collect(); 262 (*m_uno_cli_env->release)( m_uno_cli_env ); 263 (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); 264 } 265 266 267 268 } //namespace cli_uno 269 270 extern "C" 271 { 272 273 namespace cli_uno 274 { 275 //-------------------------------------------------------------------------------------------------- 276 void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env ) 277 SAL_THROW_EXTERN_C() 278 { 279 uno_cli_env->pContext = 0; 280 } 281 282 //################################################################################################## 283 void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env ) 284 SAL_THROW_EXTERN_C() 285 { 286 //ToDo: remove when compiled with .NET 2 287 #if defined(_MSC_VER) && (_MSC_VER < 1400) 288 __crt_dll_initialize(); 289 #endif 290 291 uno_cli_env->environmentDisposing= cli_env_disposing; 292 uno_cli_env->pExtEnv = 0; 293 //Set the console to print Trace messages 294 #if OSL_DEBUG_LEVEL >= 1 295 System::Diagnostics::Trace::Listeners-> 296 Add( gcnew System::Diagnostics::TextWriterTraceListener(System::Console::Out)); 297 #endif 298 OSL_ASSERT( 0 == uno_cli_env->pContext ); 299 300 // We let the Cli_environment leak, since there is no good point where we could destruct it. 301 //dispose is not used because we would have then also synchronize the calls to proxies. If the 302 //Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points 303 //where g_cli_env is accessed. 304 //When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot 305 //member in a unmanaged class, such as Bridge. 306 CliEnvHolder::g_cli_env = gcnew Cli_environment(); 307 } 308 //################################################################################################## 309 void SAL_CALL uno_ext_getMapping( 310 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) 311 SAL_THROW_EXTERN_C() 312 { 313 OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo ); 314 if (*ppMapping) 315 { 316 (*(*ppMapping)->release)( *ppMapping ); 317 *ppMapping = 0; 318 } 319 320 321 OUString const & from_env_typename = *reinterpret_cast< OUString const * >( 322 &pFrom->pTypeName ); 323 OUString const & to_env_typename = *reinterpret_cast< OUString const * >( 324 &pTo->pTypeName ); 325 326 uno_Mapping * mapping = 0; 327 328 try 329 { 330 if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) ) && 331 to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) )) 332 { 333 Bridge * bridge = new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1 334 mapping = &bridge->m_cli2uno; 335 uno_registerMapping( 336 &mapping, Bridge_free, pFrom, (uno_Environment *)pTo->pExtEnv, 0 ); 337 } 338 else if (from_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) && 339 to_env_typename.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_CLI) )) 340 { 341 Bridge * bridge = new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1 342 mapping = &bridge->m_uno2cli; 343 uno_registerMapping( 344 &mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 ); 345 } 346 } 347 catch (BridgeRuntimeError & err) 348 { 349 #if OSL_DEBUG_LEVEL >= 1 350 OString cstr_msg( 351 OUStringToOString( 352 OUSTR("[cli_uno bridge error] ") + err.m_message, RTL_TEXTENCODING_ASCII_US ) ); 353 OSL_ENSURE( 0, cstr_msg.getStr() ); 354 #else 355 (void) err; // unused 356 #endif 357 } 358 *ppMapping = mapping; 359 } 360 361 362 //################################################################################################## 363 sal_Bool SAL_CALL component_canUnload( TimeValue * ) 364 SAL_THROW_EXTERN_C() 365 { 366 return true; 367 } 368 369 } 370 } 371