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