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