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                       System::Object * args[], 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 valuse
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->get_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                     map_to_cli(
143                         &args[nPos], uno_args[nPos], param.pTypeRef,
144                         argTypes != NULL ? argTypes[nPos] : NULL, false );
145                 }
146                 catch (...)
147                 {
148                     // cleanup further uno args
149                     for ( sal_Int32 n = nPos; n < nParams; ++n )
150                     {
151                         uno_type_destructData( uno_args[n], pParams[n].pTypeRef, 0 );
152                     }
153                     // cleanup uno return value
154                     uno_type_destructData( uno_ret, return_type, 0 );
155                     throw;
156                 }
157             }
158             //cleanup args
159             if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
160                 typelib_TypeClass_ENUM != type->eTypeClass) // opt
161             {
162                 uno_type_destructData(uno_args[nPos], type, 0);
163             }
164         }
165 
166         if ((0 != return_type) &&
167             (typelib_TypeClass_VOID != return_type->eTypeClass))
168         {
169             // convert uno return value
170             try
171             {
172                 System::Object* cli_ret;
173                  map_to_cli(
174                      &cli_ret, uno_ret, return_type, 0, false);
175 				 uno_type_destructData(uno_ret, return_type, 0);
176                 return cli_ret;
177             }
178             catch (...)
179             {
180                 uno_type_destructData(uno_ret, return_type, 0);
181                 throw;
182             }
183         }
184         return 0; // void return
185     }
186     else // exception occured
187     {
188         // destruct uno in args
189         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
190         {
191             typelib_MethodParameter const & param = pParams[ nPos ];
192             if (param.bIn)
193             {
194                 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
195             }
196         }
197         map_to_cli(ppExc, uno_exc_holder.pData,
198                 uno_exc_holder.pType, NULL, false);
199         return 0;
200     }
201 }
202 
203 void Bridge::call_cli(
204     System::Object* cliI,
205     sr::MethodInfo* method,
206     typelib_TypeDescriptionReference * return_type,
207     typelib_MethodParameter * params, int nParams,
208     void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
209 {
210     System::Object *args[]=  new System::Object*[nParams];
211     for (int nPos= 0; nPos < nParams; nPos++)
212     {
213         typelib_MethodParameter const & param= params[nPos];
214         if (param.bIn)
215         {
216             map_to_cli( &args[nPos],
217                 uno_args[nPos], param.pTypeRef, 0, false);
218         }
219     }
220     System::Object* retInvoke= NULL;
221     try
222     {
223         retInvoke= method->Invoke(cliI, args);
224     }
225     catch (sr::TargetInvocationException* e)
226     {
227         System::Exception* exc= e->get_InnerException();
228         css::uno::TypeDescription td(mapCliType(exc->GetType()));
229         // memory for exception
230         std::auto_ptr< rtl_mem > memExc(rtl_mem::allocate(td.get()->nSize));
231         map_to_uno(memExc.get(), exc, td.get()->pWeakRef, false);
232         (*uno_exc)->pType= td.get()->pWeakRef;
233 		(*uno_exc)->pData= memExc.release();
234         return;
235     }
236     catch (System::Exception* e)
237     {
238         OUStringBuffer buf( 128 );
239         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
240                              "Unexspected exception during invocation of cli object. "
241                              "Original message is: \n") );
242         buf.append(mapCliString(e->get_Message()));
243         throw BridgeRuntimeError( buf.makeStringAndClear() );
244     }
245 
246     //convert out, in/out params
247     for (int nPos = 0; nPos < nParams; ++nPos )
248     {
249         typelib_MethodParameter const & param = params[ nPos ];
250 
251         if (param.bOut)
252         {
253             try
254             {
255                 map_to_uno(
256                     uno_args[ nPos ], args[ nPos ], param.pTypeRef,
257                          sal_True == param.bIn /* assign if inout */);
258                      // out array
259             }
260             catch (...)
261             {
262                 // cleanup uno pure out
263                 for ( sal_Int32 n = 0; n < nPos; ++n )
264                 {
265                     typelib_MethodParameter const & param = params[ n ];
266                     if (! param.bIn)
267                         uno_type_destructData( uno_args[ n ], param.pTypeRef, 0 );
268                 }
269                 throw;
270             }
271         }
272     }
273     // return value
274     if (0 != return_type)
275     {
276         map_to_uno(
277             uno_ret, retInvoke, return_type, false /* no assign */);
278     }
279     // no exception occured
280     *uno_exc = 0;
281 }
282 
283 
284 
285 
286 }
287