xref: /trunk/main/cli_ure/source/uno_bridge/cli_bridge.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
Mapping_acquire(uno_Mapping * mapping)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 //--------------------------------------------------------------------------------------------------
Mapping_release(uno_Mapping * mapping)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 //--------------------------------------------------------------------------------------------------
Mapping_cli2uno(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)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 //--------------------------------------------------------------------------------------------------
Mapping_uno2cli(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)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 //__________________________________________________________________________________________________
Bridge_free(uno_Mapping * mapping)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  */
acquire() const203 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 //__________________________________________________________________________________________________
release() const222 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 //__________________________________________________________________________________________________
Bridge(uno_Environment * uno_cli_env,uno_ExtEnvironment * uno_env,bool registered_cli2uno)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 //__________________________________________________________________________________________________
~Bridge()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 //--------------------------------------------------------------------------------------------------
cli_env_disposing(uno_Environment * uno_cli_env)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 //##################################################################################################
uno_initEnvironment(uno_Environment * uno_cli_env)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 //##################################################################################################
uno_ext_getMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo)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 //##################################################################################################
component_canUnload(TimeValue *)363 sal_Bool SAL_CALL component_canUnload( TimeValue * )
364     SAL_THROW_EXTERN_C()
365 {
366     return true;
367 }
368 
369 }
370 }
371