xref: /trunk/main/cli_ure/source/uno_bridge/cli_uno.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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 <sal/alloca.h>
28 #include "rtl/ustrbuf.hxx"
29 #include "cli_base.h"
30 #include "cli_bridge.h"
31 
32 namespace sr=System::Reflection;
33 namespace css=com::sun::star;
34 using namespace rtl;
35 
36 namespace cli_uno
37 {
38 
39 union largest
40 {
41     sal_Int64 n;
42     double d;
43     void * p;
44     uno_Any a;
45 };
46 
47 System::Object ^ Bridge::call_uno(uno_Interface * pUnoI,
48                       typelib_TypeDescription* member_td,
49                       typelib_TypeDescriptionReference * return_type,
50                       sal_Int32 nParams, typelib_MethodParameter const * pParams,
51                       cli::array< System::Object ^ > ^ args, cli::array< System::Type ^ > ^ argTypes,
52                       System::Object ^* ppExc) const
53 {
54     // return mem
55     sal_Int32 return_size = sizeof (largest);
56     if ((0 != return_type) &&
57         (typelib_TypeClass_STRUCT == return_type->eTypeClass ||
58          typelib_TypeClass_EXCEPTION == return_type->eTypeClass))
59     {
60         TypeDescr return_td( return_type );
61         if (return_td.get()->nSize > sizeof (largest))
62             return_size = return_td.get()->nSize;
63     }
64     //Prepare memory that contains all converted arguments and return values
65     //The memory block contains first pointers to the arguments which are in the same block
66     // For example, 2 arguments, 1 ret.
67     //
68     //      | Pointer
69     //      | Pointer
70     //      | Return value
71     //      | Arg 1
72     //      | Arg 2
73     //
74     // If an argument is larger then union largest, such as some structures, then the pointer
75     // points to an extra block of memory. The same goes for a big return value.
76 
77     char * mem = (char *)alloca(
78         (nParams * sizeof (void *)) + return_size + (nParams * sizeof (largest)) );
79     //array of pointers to args
80     void ** uno_args = (void **)mem;
81     //If an attribute is set, then uno_ret must be null, e.g void setAttribute(int )
82     void * uno_ret= NULL;
83     if ( !(member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE && nParams == 1))
84         uno_ret = (mem + (nParams * sizeof (void *)));
85     largest * uno_args_mem = (largest *)(mem + (nParams * sizeof (void *)) + return_size);
86 
87     OSL_ASSERT( (0 == nParams) || (nParams == args->Length) );
88     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
89     {
90         typelib_MethodParameter const & param = pParams[ nPos ];
91         typelib_TypeDescriptionReference * type = param.pTypeRef;
92 
93         uno_args[ nPos ] = &uno_args_mem[ nPos ];
94         if (typelib_TypeClass_STRUCT == type->eTypeClass ||
95             typelib_TypeClass_EXCEPTION == type->eTypeClass)
96         {
97             TypeDescr td( type );
98             if (td.get()->nSize > sizeof (largest))
99                 uno_args[ nPos ] = alloca( td.get()->nSize );
100         }
101 
102         if (param.bIn)
103         {
104             try
105             {
106                 // in, in/out params
107                 map_to_uno(
108                     uno_args[ nPos ],args[nPos] , type, false /* no assign */);
109             }
110             catch (...)
111             {
112                 // cleanup uno in args
113                 for (sal_Int32 n = 0; n < nPos; ++n)
114                 {
115                     typelib_MethodParameter const & param = pParams[n];
116                     if (param.bIn)
117                     {
118                         uno_type_destructData(uno_args[n], param.pTypeRef, 0);
119                     }
120                 }
121                 throw;
122             }
123         }
124     }
125     uno_Any uno_exc_holder;
126     uno_Any * uno_exc = &uno_exc_holder;
127     // call binary uno
128 
129     (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
130 
131     if (0 == uno_exc)
132     {
133         // convert out args; destruct uno args
134         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
135         {
136             typelib_MethodParameter const & param = pParams[ nPos ];
137             typelib_TypeDescriptionReference * type = param.pTypeRef;
138             if (param.bOut)
139             {
140                 try
141                 {
142                     // A cli::array element has no native address, so the
143                     // out-parameter goes through a local and is assigned back.
144                     System::Object ^ cliArg = nullptr;
145                     map_to_cli(
146                         &cliArg, uno_args[nPos], param.pTypeRef,
147                         argTypes != nullptr ? argTypes[nPos] : nullptr, false );
148                     args[nPos] = cliArg;
149                 }
150                 catch (...)
151                 {
152                     // cleanup further uno args
153                     for ( sal_Int32 n = nPos; n < nParams; ++n )
154                     {
155                         uno_type_destructData( uno_args[n], pParams[n].pTypeRef, 0 );
156                     }
157                     // cleanup uno return value
158                     uno_type_destructData( uno_ret, return_type, 0 );
159                     throw;
160                 }
161             }
162             //cleanup args
163             if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
164                 typelib_TypeClass_ENUM != type->eTypeClass) // opt
165             {
166                 uno_type_destructData(uno_args[nPos], type, 0);
167             }
168         }
169 
170         if ((0 != return_type) &&
171             (typelib_TypeClass_VOID != return_type->eTypeClass))
172         {
173             // convert uno return value
174             try
175             {
176                 System::Object ^ cli_ret;
177                  map_to_cli(
178                      &cli_ret, uno_ret, return_type, nullptr, false);
179                  uno_type_destructData(uno_ret, return_type, 0);
180                 return cli_ret;
181             }
182             catch (...)
183             {
184                 uno_type_destructData(uno_ret, return_type, 0);
185                 throw;
186             }
187         }
188         return 0; // void return
189     }
190     else // exception occurred
191     {
192         // destruct uno in args
193         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
194         {
195             typelib_MethodParameter const & param = pParams[ nPos ];
196             if (param.bIn)
197             {
198                 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
199             }
200         }
201         map_to_cli(ppExc, uno_exc_holder.pData,
202                 uno_exc_holder.pType, nullptr, false);
203         return 0;
204     }
205 }
206 
207 void Bridge::call_cli(
208     System::Object ^ cliI,
209     sr::MethodInfo ^ method,
210     typelib_TypeDescriptionReference * return_type,
211     typelib_MethodParameter * params, int nParams,
212     void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
213 {
214     cli::array< System::Object ^ > ^ args =  gcnew cli::array< System::Object ^ >( nParams );
215     for (int nPos= 0; nPos < nParams; nPos++)
216     {
217         typelib_MethodParameter const & param= params[nPos];
218         if (param.bIn)
219         {
220             System::Object ^ cliArg = nullptr;
221             map_to_cli( &cliArg,
222                 uno_args[nPos], param.pTypeRef, nullptr, false);
223             args[nPos] = cliArg;
224         }
225     }
226     System::Object ^ retInvoke= nullptr;
227     try
228     {
229         retInvoke= method->Invoke(cliI, args);
230     }
231     catch (sr::TargetInvocationException ^ e)
232     {
233         System::Exception ^ exc= e->InnerException;
234         css::uno::TypeDescription td(mapCliType(exc->GetType()));
235         // memory for exception
236         std::auto_ptr< rtl_mem > memExc(rtl_mem::allocate(td.get()->nSize));
237         map_to_uno(memExc.get(), exc, td.get()->pWeakRef, false);
238         (*uno_exc)->pType= td.get()->pWeakRef;
239         (*uno_exc)->pData= memExc.release();
240         return;
241     }
242     catch (System::Exception ^ e)
243     {
244         OUStringBuffer buf( 128 );
245         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
246                              "Unexpected exception during invocation of cli object. "
247                              "Original message is: \n") );
248         buf.append(mapCliString(e->Message));
249         throw BridgeRuntimeError( buf.makeStringAndClear() );
250     }
251 
252     //convert out, in/out params
253     for (int nPos = 0; nPos < nParams; ++nPos )
254     {
255         typelib_MethodParameter const & param = params[ nPos ];
256 
257         if (param.bOut)
258         {
259             try
260             {
261                 map_to_uno(
262                     uno_args[ nPos ], args[ nPos ], param.pTypeRef,
263                          sal_True == param.bIn /* assign if inout */);
264                      // out array
265             }
266             catch (...)
267             {
268                 // cleanup uno pure out
269                 for ( sal_Int32 n = 0; n < nPos; ++n )
270                 {
271                     typelib_MethodParameter const & param = params[ n ];
272                     if (! param.bIn)
273                         uno_type_destructData( uno_args[ n ], param.pTypeRef, 0 );
274                 }
275                 throw;
276             }
277         }
278     }
279     // return value
280     if (0 != return_type)
281     {
282         map_to_uno(
283             uno_ret, retInvoke, return_type, false /* no assign */);
284     }
285     // no exception occurred
286     *uno_exc = 0;
287 }
288 
289 
290 
291 
292 }
293