1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcclr.h>
21 #if !defined WIN32_LEAN_AND_MEAN
22 # define WIN32_LEAN_AND_MEAN
23 #endif
24 #include <windows.h>
25 #include "uno/environment.hxx"
26 #include "uno/lbnames.h"
27 #include "uno/mapping.hxx"
28 #include "typelib/typedescription.hxx"
29 #include "rtl/ustring.hxx"
30 #include <sal/log.hxx>
31 
32 #include "cli_bridge.h"
33 #include "cli_proxy.h"
34 
35 namespace sri= System::Runtime::InteropServices;
36 
37 namespace cli_uno
38 {
39 
40 extern "C"
41 {
Mapping_acquire(uno_Mapping * mapping)42 void SAL_CALL Mapping_acquire( uno_Mapping * mapping )
43     SAL_THROW_EXTERN_C()
44 {
45     Mapping const * that = static_cast< Mapping const * >( mapping );
46      that->m_bridge->acquire();
47 }
48 
Mapping_release(uno_Mapping * mapping)49 void SAL_CALL Mapping_release( uno_Mapping * mapping )
50     SAL_THROW_EXTERN_C()
51 {
52     Mapping const * that = static_cast< Mapping const * >( mapping );
53     that->m_bridge->release();
54 }
55 
56 
Mapping_cli2uno(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)57 void SAL_CALL Mapping_cli2uno(
58     uno_Mapping * mapping, void ** ppOut,
59     void * pIn, typelib_InterfaceTypeDescription * td )
60     SAL_THROW_EXTERN_C()
61 {
62     uno_Interface ** ppUnoI = (uno_Interface **)ppOut;
63     intptr_t  cliI = (intptr_t)pIn;
64 
65     OSL_ENSURE( ppUnoI && td, "### null ptr!" );
66 
67      if (0 != *ppUnoI)
68      {
69          uno_Interface * pUnoI = *(uno_Interface **)ppUnoI;
70          (*pUnoI->release)( pUnoI );
71          *ppUnoI = 0;
72      }
73     try
74     {
75         Mapping const * that = static_cast< Mapping const * >( mapping );
76         Bridge * bridge = that->m_bridge;
77 
78         if (0 != cliI)
79         {
80             System::Object^ cliObj= sri::GCHandle::FromIntPtr(IntPtr(cliI)).Target;
81             (*ppOut)= bridge->map_cli2uno(cliObj, (typelib_TypeDescription*) td);
82         }
83     }
84     catch (BridgeRuntimeError & err)
85     {
86         (void) err;
87         SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
88     }
89 }
90 
Mapping_uno2cli(uno_Mapping * mapping,void ** ppOut,void * pIn,typelib_InterfaceTypeDescription * td)91 void SAL_CALL Mapping_uno2cli(
92     uno_Mapping * mapping, void ** ppOut,
93     void * pIn, typelib_InterfaceTypeDescription * td )
94     SAL_THROW_EXTERN_C()
95 {
96     try
97     {
98         OSL_ENSURE( td && ppOut, "### null ptr!" );
99         OSL_ENSURE( (sizeof(System::Char) == sizeof(sal_Unicode))
100                     && (sizeof(System::Boolean) == sizeof(sal_Bool))
101                     && (sizeof(System::SByte) == sizeof(sal_Int8))
102                     && (sizeof(System::Int16) == sizeof(sal_Int16))
103                     && (sizeof(System::UInt16) == sizeof(sal_uInt16))
104                     && (sizeof(System::Int32) == sizeof(sal_Int32))
105                     && (sizeof(System::UInt32) == sizeof(sal_uInt32))
106                     && (sizeof(System::Int64) == sizeof(sal_Int64))
107                     && (sizeof(System::UInt64) == sizeof(sal_uInt64))
108                     && (sizeof(System::Single) == sizeof(float))
109                     && (sizeof(System::Double) == sizeof(double)),
110                     "[cli_uno bridge] incompatible .NET data types");
111         intptr_t * ppDNetI = (intptr_t *)ppOut;
112         uno_Interface * pUnoI = (uno_Interface *)pIn;
113 
114         Mapping const * that = static_cast< Mapping const * >( mapping );
115         Bridge  * bridge = that->m_bridge;
116 
117         if (0 != *ppDNetI)
118         {
119             sri::GCHandle::FromIntPtr(IntPtr(ppDNetI)).Free();
120         }
121 
122         if (0 != pUnoI)
123         {
124             System::Object^ cliI=  bridge->map_uno2cli(pUnoI, td);
125             intptr_t ptr= NULL;
126             if(cliI)
127             {
128                 ptr= sri::GCHandle::ToIntPtr(sri::GCHandle::Alloc(cliI))
129 #ifdef _WIN64
130                     .ToInt64();
131 #else /* defined(_WIN32) */
132                     .ToInt32();
133 #endif
134             }
135             (*ppOut)= reinterpret_cast<void*>(ptr);
136         }
137     }
138     catch (BridgeRuntimeError & err)
139     {
140         (void) err;
141         SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
142     }
143 }
144 
145 
Bridge_free(uno_Mapping * mapping)146 void SAL_CALL Bridge_free( uno_Mapping * mapping )
147     SAL_THROW_EXTERN_C()
148 {
149     Mapping * that = static_cast< Mapping * >( mapping );
150     delete that->m_bridge;
151 }
152 
153 } //extern C
154 } //namespace
155 
156 namespace cli_uno
157 {
158 
159 
160 /** ToDo
161     I doubt that the case that the ref count raises from 0 to 1
162     can occur.  uno_ext_getMapping returns an acquired mapping. Every time
163     that function is called then a new mapping is created. Following the
164     rules of ref counted objects, then if the ref count is null no one has
165     a reference to the object anymore. Hence no one can call acquire. If someone
166     calls acquire then they must have kept an unacquired pointer which is
167     illegal.
168  */
acquire() const169 void Bridge::acquire()  const
170 {
171     if (1 == osl_atomic_increment( &m_ref ))
172     {
173         if (m_registered_cli2uno)
174         {
175             uno_Mapping * mapping = const_cast<Mapping*>(&m_cli2uno);
176             uno_registerMapping(
177                 & const_cast<uno_Mapping*>(mapping), Bridge_free, m_uno_cli_env, (uno_Environment *)m_uno_env, 0 );
178         }
179         else
180         {
181             uno_Mapping * mapping = const_cast<Mapping*>(&m_uno2cli);
182             uno_registerMapping(
183                 &mapping, Bridge_free, (uno_Environment *)m_uno_env, m_uno_cli_env, 0 );
184         }
185     }
186 }
187 
release() const188 void Bridge::release() const
189 {
190     if (! osl_atomic_decrement( &m_ref ))
191     {
192         uno_revokeMapping(
193             m_registered_cli2uno
194             ?  const_cast<Mapping*>(&m_cli2uno)
195             :  const_cast<Mapping*>(&m_uno2cli)  );
196    }
197 }
198 
Bridge(uno_Environment * uno_cli_env,uno_ExtEnvironment * uno_env,bool registered_cli2uno)199 Bridge::Bridge(
200     uno_Environment * uno_cli_env, uno_ExtEnvironment * uno_env,
201     bool registered_cli2uno )
202     : m_ref( 1 ),
203       m_uno_env( uno_env ),
204       m_uno_cli_env( uno_cli_env ),
205       m_registered_cli2uno( registered_cli2uno )
206 {
207     OSL_ASSERT( 0 != m_uno_cli_env && 0 != m_uno_env );
208     (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env );
209     (*m_uno_cli_env->acquire)( m_uno_cli_env );
210 
211     // cli2uno
212     m_cli2uno.acquire = Mapping_acquire;
213     m_cli2uno.release = Mapping_release;
214     m_cli2uno.mapInterface = Mapping_cli2uno;
215     m_cli2uno.m_bridge = this;
216     // uno2cli
217     m_uno2cli.acquire = Mapping_acquire;
218     m_uno2cli.release = Mapping_release;
219     m_uno2cli.mapInterface = Mapping_uno2cli;
220     m_uno2cli.m_bridge = this;
221 
222 }
223 
224 
~Bridge()225 Bridge::~Bridge()
226 {
227     //System::GC::Collect();
228     (*m_uno_cli_env->release)( m_uno_cli_env );
229     (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env );
230 }
231 
232 
233 } //namespace cli_uno
234 
235 extern "C"
236 {
237 
238 namespace cli_uno
239 {
240 
cli_env_disposing(uno_Environment * uno_cli_env)241 void SAL_CALL cli_env_disposing( uno_Environment * uno_cli_env )
242     SAL_THROW_EXTERN_C()
243 {
244     uno_cli_env->pContext = 0;
245 }
246 
247 
uno_initEnvironment(uno_Environment * uno_cli_env)248 SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_initEnvironment( uno_Environment * uno_cli_env )
249     SAL_THROW_EXTERN_C()
250 {
251     //ToDo: remove when compiled with .NET 2
252 
253     // Unclear whether the above comment refers to this whole function
254     // or a call to __crt_dll_initialize() that used to be here for
255     // _MSC_VER < 1400
256 
257     uno_cli_env->environmentDisposing= cli_env_disposing;
258     uno_cli_env->pExtEnv = 0;
259     //Set the console to print Trace messages
260 #if OSL_DEBUG_LEVEL >= 1
261     System::Diagnostics::Trace::Listeners->
262             Add( gcnew System::Diagnostics::TextWriterTraceListener(System::Console::Out));
263 #endif
264     OSL_ASSERT( 0 == uno_cli_env->pContext );
265 
266     // We let the Cli_environment leak, since there is no good point where we could destruct it.
267     //dispose is not used because we would have then also synchronize the calls to proxies. If the
268     //Cli_environment is disposed, we must prevent all calls, otherwise we may crash at points
269     //where g_cli_env is accessed.
270     //When we compile the bridge with .NET 2 then we can again hold g_cli_env as a static gcroot
271     //member in a unmanaged class, such as Bridge.
272     CliEnvHolder::g_cli_env = gcnew Cli_environment();
273 }
274 
uno_ext_getMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo)275 SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_ext_getMapping(
276     uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
277     SAL_THROW_EXTERN_C()
278 {
279     OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo );
280     if (*ppMapping)
281     {
282         (*(*ppMapping)->release)( *ppMapping );
283         *ppMapping = 0;
284     }
285 
286 
287     OUString const & from_env_typename = OUString::unacquired(
288         &pFrom->pTypeName );
289     OUString const & to_env_typename = OUString::unacquired( &pTo->pTypeName );
290 
291     uno_Mapping * mapping = 0;
292 
293     try
294     {
295         if ( from_env_typename == UNO_LB_CLI && to_env_typename == UNO_LB_UNO )
296         {
297             Bridge * bridge = new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
298             mapping = &bridge->m_cli2uno;
299             uno_registerMapping(
300                 &mapping, Bridge_free, pFrom, (uno_Environment *)pTo->pExtEnv, 0 );
301         }
302         else if ( from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_CLI )
303         {
304             Bridge * bridge = new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
305             mapping = &bridge->m_uno2cli;
306             uno_registerMapping(
307                 &mapping, Bridge_free, (uno_Environment *)pFrom->pExtEnv, pTo, 0 );
308         }
309     }
310     catch (BridgeRuntimeError & err)
311     {
312         (void) err;
313         SAL_WARN( "cli", "[cli_uno bridge error] " << err.m_message );
314     }
315     *ppMapping = mapping;
316 }
317 
318 }
319 }
320 
321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
322