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 #include "typelib/typedescription.h" 27 #include "rtl/ustrbuf.hxx" 28 #include "com/sun/star/uno/RuntimeException.hpp" 29 #include "osl/mutex.hxx" 30 #include "cli_proxy.h" 31 #include "cli_base.h" 32 #include "cli_bridge.h" 33 34 #using <mscorlib.dll> 35 #using <cli_ure.dll> 36 #using <cli_uretypes.dll> 37 38 namespace sr = System::Reflection; 39 namespace st = System::Text; 40 namespace sre = System::Reflection::Emit; 41 namespace sc = System::Collections; 42 namespace srrm = System::Runtime::Remoting::Messaging; 43 namespace srr = System::Runtime::Remoting; 44 namespace srrp = System::Runtime::Remoting::Proxies; 45 namespace sri = System::Runtime::InteropServices; 46 namespace sd = System::Diagnostics; 47 namespace css = com::sun::star; 48 namespace ucss = unoidl::com::sun::star; 49 50 using namespace cli_uno; 51 using namespace rtl; 52 extern "C" 53 { 54 //------------------------------------------------------------------------------ 55 void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy ) 56 SAL_THROW_EXTERN_C(); 57 //------------------------------------------------------------------------------ 58 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) 59 SAL_THROW_EXTERN_C(); 60 //------------------------------------------------------------------------------ 61 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) 62 SAL_THROW_EXTERN_C(); 63 //------------------------------------------------------------------------------ 64 void SAL_CALL cli_proxy_dispatch( 65 uno_Interface * pUnoI, typelib_TypeDescription const * member_td, 66 void * uno_ret, void * uno_args[], uno_Any ** uno_exc ) 67 SAL_THROW_EXTERN_C(); 68 69 70 } 71 72 namespace cli_uno 73 { 74 75 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI, 76 typelib_InterfaceTypeDescription* td): 77 78 m_unoI(unoI), 79 m_typeDesc(td), 80 m_bridge(bridge) 81 { 82 m_bridge->acquire(); 83 m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td)); 84 m_unoI->acquire(m_unoI); 85 typelib_typedescription_acquire(&m_typeDesc->aBase); 86 if ( ! m_typeDesc->aBase.bComplete) 87 { 88 typelib_TypeDescription* _pt = &m_typeDesc->aBase; 89 sal_Bool bComplete = ::typelib_typedescription_complete( & _pt); 90 if( ! bComplete) 91 { 92 OUStringBuffer buf( 128 ); 93 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( 94 "cannot make type complete: ") ); 95 buf.append( *reinterpret_cast< OUString const * >( 96 & m_typeDesc->aBase.pTypeName)); 97 throw BridgeRuntimeError(buf.makeStringAndClear()); 98 } 99 } 100 } 101 UnoInterfaceInfo::~UnoInterfaceInfo() 102 { 103 //accessing unmanaged objects is ok. 104 m_bridge->m_uno_env->revokeInterface( 105 m_bridge->m_uno_env, m_unoI ); 106 m_bridge->release(); 107 108 m_unoI->release(m_unoI); 109 typelib_typedescription_release( 110 reinterpret_cast<typelib_TypeDescription*>(m_typeDesc)); 111 } 112 113 UnoInterfaceProxy::UnoInterfaceProxy( 114 Bridge * bridge, 115 uno_Interface * pUnoI, 116 typelib_InterfaceTypeDescription* pTD, 117 const OUString& oid ) 118 :RealProxy(__typeof(MarshalByRefObject)), 119 m_bridge(bridge), 120 m_oid(mapUnoString(oid.pData)), 121 m_sTypeName(m_system_Object_String) 122 { 123 m_bridge->acquire(); 124 // create the list that holds all UnoInterfaceInfos 125 m_listIfaces = new ArrayList(10); 126 m_numUnoIfaces = 0; 127 m_listAdditionalProxies = new ArrayList(); 128 m_nlistAdditionalProxies = 0; 129 //put the information of the first UNO interface into the arraylist 130 #if OSL_DEBUG_LEVEL >= 2 131 _numInterfaces = 0; 132 _sInterfaces = NULL; 133 #endif 134 addUnoInterface(pUnoI, pTD); 135 136 } 137 138 UnoInterfaceProxy::~UnoInterfaceProxy() 139 { 140 #if OSL_DEBUG_LEVEL >= 2 141 sd::Trace::WriteLine(System::String::Format( 142 new System::String(S"cli uno bridge: Destroying proxy " 143 S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "), 144 m_oid)); 145 146 sd::Trace::WriteLine( mapUnoString(_sInterfaces)); 147 rtl_uString_release(_sInterfaces); 148 #endif 149 //m_bridge is unmanaged, therefore we can access it in this finalizer 150 CliEnvHolder::g_cli_env->revokeInterface(m_oid); 151 m_bridge->release(); 152 } 153 154 155 System::Object* UnoInterfaceProxy::create( 156 Bridge * bridge, 157 uno_Interface * pUnoI, 158 typelib_InterfaceTypeDescription* pTD, 159 const OUString& oid) 160 { 161 UnoInterfaceProxy* proxyHandler= 162 new UnoInterfaceProxy(bridge, pUnoI, pTD, oid); 163 System::Object* proxy= proxyHandler->GetTransparentProxy(); 164 CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData)); 165 return proxy; 166 } 167 168 169 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI, 170 typelib_InterfaceTypeDescription* pTd) 171 { 172 sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator(); 173 System::Threading::Monitor::Enter(this); 174 try 175 { 176 while (enumInfos->MoveNext()) 177 { 178 UnoInterfaceInfo* info = static_cast<UnoInterfaceInfo*>( 179 enumInfos->Current); 180 #if OSL_DEBUG_LEVEL > 1 181 System::Type * t1; 182 System::Type * t2; 183 t1 = mapUnoType( 184 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) ); 185 t2 = mapUnoType( 186 reinterpret_cast<typelib_TypeDescription*>(pTd) ); 187 #endif 188 if (typelib_typedescription_equals( 189 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc), 190 reinterpret_cast<typelib_TypeDescription*>(pTd))) 191 { 192 return; 193 } 194 } 195 OUString oid(mapCliString(m_oid)); 196 (*m_bridge->m_uno_env->registerInterface)( 197 m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ), 198 oid.pData, pTd); 199 //This proxy does not contain the uno_Interface. Add it. 200 m_listIfaces->Add(new UnoInterfaceInfo(m_bridge, pUnoI, pTd)); 201 m_numUnoIfaces = m_listIfaces->Count; 202 #if OSL_DEBUG_LEVEL >= 2 203 System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>( 204 m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName; 205 sd::Trace::WriteLine(System::String::Format( 206 new System::String(S"cli uno bridge: Creating proxy for uno object, " 207 S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName)); 208 // add to the string that contains all interface names 209 _numInterfaces ++; 210 OUStringBuffer buf(512); 211 buf.appendAscii("\t"); 212 buf.append( OUString::valueOf((sal_Int32)_numInterfaces)); 213 buf.appendAscii(". "); 214 buf.append(mapCliString(sInterfaceName)); 215 buf.appendAscii("\n"); 216 OUString _sNewInterface = buf.makeStringAndClear(); 217 rtl_uString * __pin * pp_sInterfaces = & _sInterfaces; 218 rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces, 219 _sNewInterface.pData); 220 #endif 221 } 222 __finally { 223 System::Threading::Monitor::Exit(this); 224 } 225 } 226 227 228 // IRemotingTypeInfo 229 bool UnoInterfaceProxy::CanCastTo(System::Type* fromType, 230 System::Object*) 231 { 232 if (fromType == __typeof(System::Object)) // trivial case 233 return true; 234 235 System::Threading::Monitor::Enter(this); 236 try 237 { 238 if (0 != findInfo( fromType )) // proxy supports demanded interface 239 return true; 240 241 //query an uno interface for the required type 242 243 // we use the first interface in the list (m_listIfaces) to make 244 // the queryInterface call 245 UnoInterfaceInfo* info = 246 static_cast<UnoInterfaceInfo*>(m_listIfaces->get_Item(0)); 247 css::uno::TypeDescription membertd( 248 reinterpret_cast<typelib_InterfaceTypeDescription*>( 249 info->m_typeDesc)->ppAllMembers[0]); 250 System::Object *args[] = new System::Object*[1]; 251 252 args[0] = fromType; 253 __box uno::Any * pAny; 254 System::Object* pException = NULL; 255 256 pAny= static_cast<__box uno::Any *>( 257 m_bridge->call_uno( 258 info->m_unoI, 259 membertd.get(), 260 ((typelib_InterfaceMethodTypeDescription*) 261 membertd.get())->pReturnTypeRef, 262 1, 263 ((typelib_InterfaceMethodTypeDescription*) 264 membertd.get())->pParams, 265 args, NULL, &pException) ); 266 267 // handle regular exception from target 268 OSL_ENSURE( 269 0 == pException, 270 OUStringToOString( 271 mapCliString( pException->ToString()), 272 RTL_TEXTENCODING_UTF8 ).getStr() ); 273 274 if (pAny->Type != __typeof (void)) // has value? 275 { 276 if (0 != findInfo( fromType )) 277 { 278 // proxy now supports demanded interface 279 return true; 280 } 281 282 // via aggregation: it is possible that queryInterface() returns 283 // and interface with a different oid. 284 // That way, this type is supported for the CLI 285 // interpreter (CanCastTo() returns true) 286 ::System::Object * obj = pAny->Value; 287 OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) ); 288 if (srr::RemotingServices::IsTransparentProxy( obj )) 289 { 290 UnoInterfaceProxy * proxy = 291 static_cast< UnoInterfaceProxy * >( 292 srr::RemotingServices::GetRealProxy( obj ) ); 293 OSL_ASSERT( 0 != proxy->findInfo( fromType ) ); 294 m_listAdditionalProxies->Add( proxy ); 295 m_nlistAdditionalProxies = m_listAdditionalProxies->Count; 296 OSL_ASSERT( 0 != findInfo( fromType ) ); 297 return true; 298 } 299 } 300 } 301 catch (BridgeRuntimeError& e) 302 { 303 (void) e; // avoid warning 304 OSL_ENSURE( 305 0, OUStringToOString( 306 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() ); 307 } 308 catch (System::Exception* e) 309 { 310 System::String* msg= new System::String( 311 S"An unexpected CLI exception occurred in " 312 S"UnoInterfaceProxy::CanCastTo(). Original" 313 S"message: \n"); 314 msg= System::String::Concat(msg, e->get_Message()); 315 OSL_ENSURE( 316 0, OUStringToOString( 317 mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() ); 318 } 319 catch (...) 320 { 321 OSL_ENSURE( 322 0, "An unexpected native C++ exception occurred in " 323 "UnoInterfaceProxy::CanCastTo()" ); 324 } 325 __finally 326 { 327 System::Threading::Monitor::Exit(this); 328 } 329 return false; 330 } 331 332 srrm::IMessage* UnoInterfaceProxy::invokeObject( 333 sc::IDictionary* props, 334 srrm::LogicalCallContext* context, 335 srrm::IMethodCallMessage* mcm) 336 { 337 System::Object* retMethod = 0; 338 System::String* sMethod = static_cast<System::String*> 339 (props->get_Item(m_methodNameString)); 340 System::Object* args[] = static_cast<System::Object*[]>( 341 props->get_Item(m_ArgsString)); 342 if (m_Equals_String->Equals(sMethod)) 343 { 344 // Object.Equals 345 OSL_ASSERT(args->get_Length() == 1); 346 srrp::RealProxy* rProxy = srr::RemotingServices::GetRealProxy(args[0]); 347 bool bDone = false; 348 if (rProxy) 349 { 350 UnoInterfaceProxy* unoProxy = 351 dynamic_cast<UnoInterfaceProxy*>(rProxy); 352 if (unoProxy) 353 { 354 bool b = m_oid->Equals(unoProxy->getOid()); 355 retMethod = __box(b); 356 bDone = true; 357 } 358 } 359 if (bDone == false) 360 { 361 //no proxy or not our proxy, therefore Equals must be false 362 retMethod = __box(false); 363 } 364 } 365 else if (m_GetHashCode_String->Equals(sMethod)) 366 { 367 // Object.GetHashCode 368 int nHash = m_oid->GetHashCode(); 369 retMethod = __box(nHash); 370 } 371 else if (m_GetType_String->Equals(sMethod)) 372 { 373 // Object.GetType 374 retMethod = __typeof(System::Object); 375 } 376 else if (m_ToString_String->Equals(sMethod)) 377 { 378 // Object.ToString 379 st::StringBuilder* sb = new st::StringBuilder(256); 380 // sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}" 381 // S". OID: {1}", m_type->ToString(), m_oid); 382 sb->AppendFormat(S"Uno object proxy. OID: {0}", m_oid); 383 retMethod = sb->ToString(); 384 } 385 else 386 { 387 //Either Object has new functions or a protected method was called 388 //which should not be possible 389 OSL_ASSERT(0); 390 } 391 srrm::IMessage* retVal= new srrm::ReturnMessage( 392 retMethod, new System::Object*[0], 0, context, mcm); 393 return retVal; 394 } 395 396 UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type ) 397 { 398 for (int i = 0; i < m_numUnoIfaces; i++) 399 { 400 UnoInterfaceInfo* tmpInfo = static_cast<UnoInterfaceInfo*>( 401 m_listIfaces->get_Item(i)); 402 if (type->IsAssignableFrom(tmpInfo->m_type)) 403 return tmpInfo; 404 } 405 for ( int i = 0; i < m_nlistAdditionalProxies; ++i ) 406 { 407 UnoInterfaceProxy * proxy = 408 static_cast< UnoInterfaceProxy * >( 409 m_listAdditionalProxies->get_Item( i ) ); 410 UnoInterfaceInfo * info = proxy->findInfo( type ); 411 if (0 != info) 412 return info; 413 } 414 return 0; 415 } 416 417 srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg) 418 { 419 try 420 { 421 sc::IDictionary* props= callmsg->Properties; 422 srrm::LogicalCallContext* context= 423 static_cast<srrm::LogicalCallContext*>( 424 props->get_Item(m_CallContextString)); 425 srrm::IMethodCallMessage* mcm= 426 static_cast<srrm::IMethodCallMessage*>(callmsg); 427 428 //Find out which UNO interface is being called 429 System::String* sTypeName = static_cast<System::String*>( 430 props->get_Item(m_typeNameString)); 431 sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(',')); 432 433 // Special Handling for System.Object methods 434 if(sTypeName->IndexOf(m_system_Object_String) != -1) 435 { 436 return invokeObject(props, context, mcm); 437 } 438 439 System::Type* typeBeingCalled = loadCliType(sTypeName); 440 UnoInterfaceInfo* info = findInfo( typeBeingCalled ); 441 OSL_ASSERT( 0 != info ); 442 443 // ToDo do without string conversion, a OUString is not needed here 444 // get the type description of the call 445 OUString usMethodName(mapCliString(static_cast<System::String*>( 446 props->get_Item(m_methodNameString)))); 447 typelib_TypeDescriptionReference ** ppAllMembers = 448 info->m_typeDesc->ppAllMembers; 449 sal_Int32 numberMembers = info->m_typeDesc->nAllMembers; 450 for ( sal_Int32 nPos = numberMembers; nPos--; ) 451 { 452 typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos]; 453 454 // check usMethodName against fully qualified usTypeName 455 // of member_type; usTypeName is of the form 456 // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>) 457 OUString const & usTypeName = 458 OUString::unacquired( & member_type->pTypeName ); 459 460 #if OSL_DEBUG_LEVEL >= 2 461 System::String * pTypeName; 462 pTypeName = mapUnoString(usTypeName.pData); 463 #endif 464 sal_Int32 offset = usTypeName.indexOf( ':' ) + 2; 465 OSL_ASSERT( 466 offset >= 2 && offset < usTypeName.getLength() 467 && usTypeName[offset - 1] == ':' ); 468 sal_Int32 remainder = usTypeName.getLength() - offset; 469 470 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass) 471 { 472 if ((usMethodName.getLength() == remainder 473 || (usMethodName.getLength() < remainder 474 && usTypeName[offset + usMethodName.getLength()] == ':')) 475 && usTypeName.match(usMethodName, offset)) 476 { 477 TypeDescr member_td( member_type ); 478 typelib_InterfaceMethodTypeDescription * method_td = 479 (typelib_InterfaceMethodTypeDescription *) 480 member_td.get(); 481 482 System::Object* args[] = static_cast<System::Object*[]>( 483 props->get_Item(m_ArgsString)); 484 System::Type* argTypes[] = static_cast<System::Type*[]>( 485 props->get_Item(m_methodSignatureString)); 486 System::Object* pExc = NULL; 487 System::Object * cli_ret = m_bridge->call_uno( 488 info->m_unoI, member_td.get(), 489 method_td->pReturnTypeRef, method_td->nParams, 490 method_td->pParams, args, argTypes, &pExc); 491 return constructReturnMessage(cli_ret, args, method_td, 492 callmsg, pExc); 493 break; 494 } 495 } 496 else 497 { 498 OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE == 499 member_type->eTypeClass ); 500 if (usMethodName.getLength() > 4 501 && (usMethodName.getLength() - 4 == remainder 502 || (usMethodName.getLength() - 4 < remainder 503 && usTypeName[ 504 offset + (usMethodName.getLength() - 4)] == ':')) 505 && usMethodName[1] == 'e' && usMethodName[2] == 't' 506 && rtl_ustr_compare_WithLength( 507 usTypeName.getStr() + offset, 508 usMethodName.getLength() - 4, 509 usMethodName.getStr() + 4, 510 usMethodName.getLength() - 4) == 0) 511 { 512 if ('g' == usMethodName[0]) 513 { 514 TypeDescr member_td( member_type ); 515 typelib_InterfaceAttributeTypeDescription * attribute_td = 516 (typelib_InterfaceAttributeTypeDescription*) 517 member_td.get(); 518 519 System::Object* pExc = NULL; 520 System::Object* cli_ret= m_bridge->call_uno( 521 info->m_unoI, member_td.get(), 522 attribute_td->pAttributeTypeRef, 523 0, 0, 524 NULL, NULL, &pExc); 525 return constructReturnMessage(cli_ret, NULL, NULL, 526 callmsg, pExc); 527 } 528 else if ('s' == usMethodName[0]) 529 { 530 TypeDescr member_td( member_type ); 531 typelib_InterfaceAttributeTypeDescription * attribute_td = 532 (typelib_InterfaceAttributeTypeDescription *) 533 member_td.get(); 534 if (! attribute_td->bReadOnly) 535 { 536 typelib_MethodParameter param; 537 param.pTypeRef = attribute_td->pAttributeTypeRef; 538 param.bIn = sal_True; 539 param.bOut = sal_False; 540 541 System::Object* args[] = 542 static_cast<System::Object*[]>( 543 props->get_Item(m_ArgsString)); 544 System::Object* pExc = NULL; 545 m_bridge->call_uno( 546 info->m_unoI, member_td.get(), 547 ::getCppuVoidType().getTypeLibType(), 548 1, ¶m, args, NULL, &pExc); 549 return constructReturnMessage(NULL, NULL, NULL, 550 callmsg, pExc); 551 } 552 else 553 { 554 return constructReturnMessage(NULL, NULL, NULL, 555 callmsg, NULL); 556 } 557 } 558 break; 559 } 560 } 561 } 562 // ToDo check if the message of the exception is not crippled 563 // the thing that should not be... no method info found! 564 OUStringBuffer buf( 64 ); 565 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( 566 "[cli_uno bridge]calling undeclared function on " 567 "interface ") ); 568 buf.append( *reinterpret_cast< OUString const * >( 569 & ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName)); 570 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); 571 buf.append( usMethodName ); 572 throw BridgeRuntimeError( buf.makeStringAndClear() ); 573 } 574 catch (BridgeRuntimeError & err) 575 { 576 srrm::IMethodCallMessage* mcm = 577 static_cast<srrm::IMethodCallMessage*>(callmsg); 578 return new srrm::ReturnMessage(new ucss::uno::RuntimeException( 579 mapUnoString(err.m_message.pData), NULL), mcm); 580 } 581 catch (System::Exception* e) 582 { 583 st::StringBuilder * sb = new st::StringBuilder(512); 584 sb->Append(new System::String( 585 S"An unexpected CLI exception occurred in " 586 S"UnoInterfaceProxy::Invoke. Original" 587 S"message: \n")); 588 sb->Append(e->get_Message()); 589 sb->Append((__wchar_t) '\n'); 590 sb->Append(e->get_StackTrace()); 591 srrm::IMethodCallMessage* mcm = 592 static_cast<srrm::IMethodCallMessage*>(callmsg); 593 return new srrm::ReturnMessage(new ucss::uno::RuntimeException( 594 sb->ToString(), NULL), mcm); 595 } 596 catch (...) 597 { 598 System::String* msg = new System::String( 599 S"An unexpected native C++ exception occurred in " 600 S"UnoInterfaceProxy::Invoke."); 601 srrm::IMethodCallMessage* mcm = 602 static_cast<srrm::IMethodCallMessage*>(callmsg); 603 return new srrm::ReturnMessage(new ucss::uno::RuntimeException( 604 msg, NULL), mcm); 605 } 606 return NULL; 607 } 608 /** If the argument args is NULL then this function is called for an attribute 609 method (either setXXX or getXXX). 610 For attributes the argument mtd is also NULL. 611 */ 612 srrm::IMessage* UnoInterfaceProxy::constructReturnMessage( 613 System::Object* cliReturn, 614 System::Object* args[], 615 typelib_InterfaceMethodTypeDescription* mtd, 616 srrm::IMessage* msg, System::Object* exc) 617 { 618 srrm::IMessage * retVal= NULL; 619 srrm::IMethodCallMessage* mcm = static_cast<srrm::IMethodCallMessage*>(msg); 620 if (exc) 621 { 622 retVal = new srrm::ReturnMessage( 623 dynamic_cast<System::Exception*>(exc), mcm); 624 } 625 else 626 { 627 sc::IDictionary* props= msg->get_Properties(); 628 srrm::LogicalCallContext* context= 629 static_cast<srrm::LogicalCallContext*>( 630 props->get_Item(m_CallContextString)); 631 if (args != NULL) 632 { 633 // Method 634 //build the array of out parameters, allocate max length 635 System::Object* arOut[]= new System::Object*[mtd->nParams]; 636 int nOut = 0; 637 for (int i= 0; i < mtd->nParams; i++) 638 { 639 if (mtd->pParams[i].bOut) 640 { 641 arOut[i]= args[i]; 642 nOut++; 643 } 644 } 645 retVal= new srrm::ReturnMessage(cliReturn, arOut, nOut, 646 context, mcm); 647 } 648 else 649 { 650 // Attribute (getXXX) 651 retVal= new srrm::ReturnMessage(cliReturn, NULL, 0, 652 context, mcm); 653 } 654 } 655 return retVal; 656 } 657 658 //################################################################################ 659 CliProxy::CliProxy(Bridge const* bridge, System::Object* cliI, 660 typelib_TypeDescription const* td, 661 const rtl::OUString& usOid): 662 m_ref(1), 663 m_bridge(bridge), 664 m_cliI(cliI), 665 m_unoType(const_cast<typelib_TypeDescription*>(td)), 666 m_usOid(usOid), 667 m_oid(mapUnoString(usOid.pData)), 668 m_nInheritedInterfaces(0) 669 { 670 m_bridge->acquire(); 671 uno_Interface::acquire = cli_proxy_acquire; 672 uno_Interface::release = cli_proxy_release; 673 uno_Interface::pDispatcher = cli_proxy_dispatch; 674 675 m_unoType.makeComplete(); 676 m_type= mapUnoType(m_unoType.get()); 677 678 makeMethodInfos(); 679 #if OSL_DEBUG_LEVEL >= 2 680 sd::Trace::WriteLine(System::String::Format( 681 new System::String(S"cli uno bridge: Creating proxy for cli object, " 682 S"id:\n\t{0}\n\t{1}"), m_oid, m_type)); 683 #endif 684 685 } 686 687 void CliProxy::makeMethodInfos() 688 { 689 #if OSL_DEBUG_LEVEL >= 2 690 System::Object* cliI; 691 System::Type* type; 692 cliI = m_cliI; 693 type = m_type; 694 #endif 695 696 if (m_type->get_IsInterface() == false) 697 return; 698 sr::MethodInfo* arThisMethods[] = m_type->GetMethods(); 699 //get the inherited interfaces 700 System::Type* arInheritedIfaces[] = m_type->GetInterfaces(); 701 m_nInheritedInterfaces = arInheritedIfaces->get_Length(); 702 //array containing the number of methods for the interface and its 703 //inherited interfaces 704 m_arInterfaceMethodCount = new int __gc [m_nInheritedInterfaces + 1]; 705 //determine the number of all interface methods, including the inherited 706 //interfaces 707 int numMethods = arThisMethods->get_Length(); 708 for (int i= 0; i < m_nInheritedInterfaces; i++) 709 { 710 numMethods += arInheritedIfaces[i]->GetMethods()->get_Length(); 711 } 712 //array containing MethodInfos of the cli object 713 m_arMethodInfos = new sr::MethodInfo*[numMethods]; 714 //array containing MethodInfos of the interface 715 m_arInterfaceMethodInfos = new sr::MethodInfo*[numMethods]; 716 //array containing the mapping of Uno interface pos to pos in 717 //m_arMethodInfos 718 m_arUnoPosToCliPos = new System::Int32[numMethods]; 719 // initialize with -1 720 for (int i = 0; i < numMethods; i++) 721 m_arUnoPosToCliPos[i] = -1; 722 723 #if OSL_DEBUG_LEVEL >= 2 724 sr::MethodInfo* arMethodInfosDbg[]; 725 sr::MethodInfo* arInterfaceMethodInfosDbg[]; 726 System::Int32 arInterfaceMethodCountDbg[]; 727 arMethodInfosDbg = m_arMethodInfos; 728 arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; 729 arInterfaceMethodCountDbg = m_arInterfaceMethodCount; 730 #endif 731 732 733 //fill m_arMethodInfos with the mappings 734 // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according 735 // to documentation 736 // but it is Type*[] instead. Bug in the framework? 737 System::Type* objType = m_cliI->GetType(); 738 try 739 { 740 int index = 0; 741 // now get the methods from the inherited interface 742 //arInheritedIfaces[0] is the direct base interface 743 //arInheritedIfaces[n] is the furthest inherited interface 744 //Start with the base interface 745 int nArLength = arInheritedIfaces->get_Length(); 746 for (;nArLength > 0; nArLength--) 747 { 748 sr::InterfaceMapping mapInherited = objType->GetInterfaceMap( 749 arInheritedIfaces[nArLength - 1]); 750 int numMethods = mapInherited.TargetMethods->get_Length(); 751 m_arInterfaceMethodCount[nArLength - 1] = numMethods; 752 for (int i = 0; i < numMethods; i++, index++) 753 { 754 m_arMethodInfos[index] = __try_cast<sr::MethodInfo*>( 755 mapInherited.TargetMethods[i]); 756 757 m_arInterfaceMethodInfos[index] = __try_cast<sr::MethodInfo*>( 758 mapInherited.InterfaceMethods[i]); 759 } 760 } 761 //At last come the methods of the furthest derived interface 762 sr::InterfaceMapping map = objType->GetInterfaceMap(m_type); 763 nArLength = map.TargetMethods->get_Length(); 764 m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength; 765 for (int i = 0; i < nArLength; i++,index++) 766 { 767 m_arMethodInfos[index]= __try_cast<sr::MethodInfo*>( 768 map.TargetMethods[i]); 769 m_arInterfaceMethodInfos[index]= __try_cast<sr::MethodInfo*>( 770 map.InterfaceMethods[i]); 771 } 772 } 773 catch (System::InvalidCastException* ) 774 { 775 OUStringBuffer buf( 128 ); 776 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( 777 "[cli_uno bridge] preparing proxy for " 778 "cli interface: ") ); 779 buf.append(mapCliString(m_type->ToString() )); 780 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" \nfailed!")); 781 throw BridgeRuntimeError( buf.makeStringAndClear() ); 782 } 783 } 784 785 sr::MethodInfo* CliProxy::getMethodInfo(int nUnoFunctionPos, 786 const rtl::OUString& usMethodName, MethodKind methodKind) 787 { 788 sr::MethodInfo* ret = NULL; 789 #if OSL_DEBUG_LEVEL >= 2 790 System::String* sMethodNameDbg; 791 sr::MethodInfo* arMethodInfosDbg[]; 792 sr::MethodInfo* arInterfaceMethodInfosDbg[]; 793 System::Int32 arInterfaceMethodCountDbg[]; 794 System::Int32 arUnoPosToCliPosDbg[]; 795 sMethodNameDbg = mapUnoString(usMethodName.pData); 796 arMethodInfosDbg = m_arMethodInfos; 797 arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos; 798 arInterfaceMethodCountDbg = m_arInterfaceMethodCount; 799 arUnoPosToCliPosDbg = m_arUnoPosToCliPos; 800 #endif 801 //deduct 3 for XInterface methods 802 nUnoFunctionPos -= 3; 803 System::Threading::Monitor::Enter(m_arUnoPosToCliPos); 804 try 805 { 806 int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos]; 807 if (cliPos != -1) 808 return m_arMethodInfos[cliPos]; 809 810 //create the method function name 811 System::String* sMethodName = mapUnoString(usMethodName.pData); 812 switch (methodKind) 813 { 814 case MK_METHOD: 815 break; 816 case MK_SET: 817 sMethodName = System::String::Concat( 818 const_cast<System::String*>(Constants::sAttributeSet), 819 sMethodName); 820 break; 821 case MK_GET: 822 sMethodName = System::String::Concat( 823 const_cast<System::String*>(Constants::sAttributeGet), 824 sMethodName); 825 break; 826 default: 827 OSL_ASSERT(0); 828 } 829 //Find the cli interface method that corresponds to the Uno method 830 // System::String* sMethodName= mapUnoString(usMethodName.pData); 831 int indexCliMethod = -1; 832 //If the cli interfaces and their methods are in the same order 833 //as they were declared (inheritance chain and within the interface) 834 //then nUnoFunctionPos should lead to the correct method. However, 835 //the documentation does not say that this ordering is given. 836 if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name)) 837 indexCliMethod = nUnoFunctionPos; 838 else 839 { 840 int cMethods = m_arInterfaceMethodInfos->get_Length(); 841 for (int i = 0; i < cMethods; i++) 842 { 843 System::String* cliMethod = m_arInterfaceMethodInfos[i]->Name; 844 if (cliMethod->Equals(sMethodName)) 845 { 846 indexCliMethod = i; 847 break; 848 } 849 } 850 } 851 if (indexCliMethod == -1) 852 { 853 OUStringBuffer buf(256); 854 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM( 855 "[cli_uno bridge] CliProxy::getMethodInfo():" 856 "cli object does not implement interface method: ")); 857 buf.append(usMethodName); 858 throw BridgeRuntimeError(buf.makeStringAndClear()); 859 return 0; 860 } 861 m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod; 862 ret = m_arMethodInfos[indexCliMethod]; 863 } 864 __finally 865 { 866 System::Threading::Monitor::Exit(m_arUnoPosToCliPos); 867 } 868 869 return ret; 870 } 871 872 CliProxy::~CliProxy() 873 { 874 #if OSL_DEBUG_LEVEL >= 2 875 sd::Trace::WriteLine(System::String::Format( 876 new System::String( 877 S"cli uno bridge: Destroying proxy for cli object, " 878 S"id:\n\t{0}\n\t{1}\n"), 879 m_oid, m_type)); 880 #endif 881 CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get())); 882 m_bridge->release(); 883 } 884 885 uno_Interface* CliProxy::create(Bridge const * bridge, 886 System::Object* cliI, 887 typelib_TypeDescription const* pTD, 888 const rtl::OUString& ousOid) 889 { 890 uno_Interface* proxy= static_cast<uno_Interface*>( 891 new CliProxy(bridge, cliI, pTD, ousOid)); 892 893 //register proxy with target environment (uno) 894 (*bridge->m_uno_env->registerProxyInterface)( 895 bridge->m_uno_env, 896 reinterpret_cast<void**>(&proxy), 897 cli_proxy_free, 898 ousOid.pData, (typelib_InterfaceTypeDescription*) pTD); 899 //register original interface 900 CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData), 901 mapUnoType((pTD))); 902 903 return proxy; 904 } 905 906 907 908 void SAL_CALL CliProxy::uno_DispatchMethod( 909 struct _uno_Interface *, 910 const struct _typelib_TypeDescription *, 911 void *, 912 void **, 913 uno_Any ** ) 914 { 915 } 916 inline void CliProxy::acquire() const 917 { 918 if (1 == osl_incrementInterlockedCount( &m_ref )) 919 { 920 // rebirth of proxy zombie 921 void * that = const_cast< CliProxy * >( this ); 922 // register at uno env 923 (*m_bridge->m_uno_env->registerProxyInterface)( 924 m_bridge->m_uno_env, &that, 925 cli_proxy_free, m_usOid.pData, 926 (typelib_InterfaceTypeDescription *)m_unoType.get() ); 927 #if OSL_DEBUG_LEVEL >= 2 928 OSL_ASSERT( this == (void const * const)that ); 929 #endif 930 } 931 } 932 //--------------------------------------------------------------------------- 933 inline void CliProxy::release() const 934 { 935 if (0 == osl_decrementInterlockedCount( &m_ref )) 936 { 937 // revoke from uno env on last release, 938 // The proxy can be resurrected if acquire is called before the uno 939 // environment calls cli_proxy_free. cli_proxy_free will 940 //delete the proxy. The environment does not acquire a registered 941 //proxy. 942 (*m_bridge->m_uno_env->revokeInterface)( 943 m_bridge->m_uno_env, const_cast< CliProxy * >( this ) ); 944 } 945 } 946 } 947 948 949 950 951 extern "C" 952 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy ) 953 SAL_THROW_EXTERN_C() 954 { 955 cli_uno::CliProxy * cliProxy = reinterpret_cast< 956 cli_uno::CliProxy * >( proxy ); 957 958 delete cliProxy; 959 } 960 961 extern "C" 962 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI ) 963 SAL_THROW_EXTERN_C() 964 { 965 CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI ); 966 cliProxy->acquire(); 967 } 968 //----------------------------------------------------------------------------- 969 extern "C" 970 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI ) 971 SAL_THROW_EXTERN_C() 972 { 973 CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI ); 974 cliProxy->release(); 975 } 976 977 //------------------------------------------------------------------------------ 978 extern "C" 979 980 void SAL_CALL cli_proxy_dispatch( 981 uno_Interface * pUnoI, typelib_TypeDescription const * member_td, 982 void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) 983 SAL_THROW_EXTERN_C() 984 { 985 CliProxy * proxy = static_cast< CliProxy* >( pUnoI ); 986 try 987 { 988 Bridge const* bridge = proxy->m_bridge; 989 990 switch (member_td->eTypeClass) 991 { 992 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 993 { 994 995 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) 996 member_td)->nPosition; 997 typelib_InterfaceTypeDescription * iface_td = 998 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); 999 OSL_ENSURE( 1000 member_pos < iface_td->nAllMembers, 1001 "### member pos out of range!" ); 1002 sal_Int32 function_pos = 1003 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; 1004 OSL_ENSURE( 1005 function_pos < iface_td->nMapFunctionIndexToMemberIndex, 1006 "### illegal function index!" ); 1007 1008 if (uno_ret) // is getter method 1009 { 1010 OUString const& usAttrName= *(rtl_uString**)& 1011 ((typelib_InterfaceMemberTypeDescription*) member_td) 1012 ->pMemberName; 1013 sr::MethodInfo* info = proxy->getMethodInfo(function_pos, 1014 usAttrName, CliProxy::MK_GET); 1015 bridge->call_cli( 1016 proxy->m_cliI, 1017 info, 1018 ((typelib_InterfaceAttributeTypeDescription *)member_td) 1019 ->pAttributeTypeRef, 1020 0, 0, // no params 1021 uno_ret, 0, uno_exc ); 1022 } 1023 else // is setter method 1024 { 1025 OUString const& usAttrName= *(rtl_uString**) & 1026 ((typelib_InterfaceMemberTypeDescription*) member_td) 1027 ->pMemberName; 1028 sr::MethodInfo* info = proxy->getMethodInfo(function_pos + 1, 1029 usAttrName, CliProxy::MK_SET); 1030 typelib_MethodParameter param; 1031 param.pTypeRef = 1032 ((typelib_InterfaceAttributeTypeDescription *)member_td) 1033 ->pAttributeTypeRef; 1034 param.bIn = sal_True; 1035 param.bOut = sal_False; 1036 1037 bridge->call_cli( 1038 proxy->m_cliI, 1039 // set follows get method 1040 info, 1041 0 /* indicates void return */, ¶m, 1, 1042 0, uno_args, uno_exc ); 1043 } 1044 break; 1045 } 1046 case typelib_TypeClass_INTERFACE_METHOD: 1047 { 1048 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *) 1049 member_td)->nPosition; 1050 typelib_InterfaceTypeDescription * iface_td = 1051 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get(); 1052 OSL_ENSURE( 1053 member_pos < iface_td->nAllMembers, 1054 "### member pos out of range!" ); 1055 sal_Int32 function_pos = 1056 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]; 1057 OSL_ENSURE( 1058 function_pos < iface_td->nMapFunctionIndexToMemberIndex, 1059 "### illegal function index!" ); 1060 1061 switch (function_pos) 1062 { 1063 case 0: // queryInterface() 1064 { 1065 TypeDescr demanded_td( 1066 *reinterpret_cast<typelib_TypeDescriptionReference **>( 1067 uno_args[0])); 1068 if (typelib_TypeClass_INTERFACE 1069 != demanded_td.get()->eTypeClass) 1070 { 1071 throw BridgeRuntimeError( 1072 OUSTR("queryInterface() call demands an INTERFACE type!")); 1073 } 1074 1075 uno_Interface * pInterface = 0; 1076 (*bridge->m_uno_env->getRegisteredInterface)( 1077 bridge->m_uno_env, 1078 (void **)&pInterface, proxy->m_usOid.pData, 1079 (typelib_InterfaceTypeDescription *)demanded_td.get() ); 1080 1081 if (0 == pInterface) 1082 { 1083 System::Type* mgdDemandedType = 1084 mapUnoType(demanded_td.get()); 1085 if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI )) 1086 { 1087 #if OSL_DEBUG_LEVEL > 0 1088 OUString usOid( 1089 mapCliString( 1090 CliEnvHolder::g_cli_env->getObjectIdentifier( 1091 proxy->m_cliI ))); 1092 OSL_ENSURE(usOid.equals( proxy->m_usOid ), 1093 "### different oids!"); 1094 #endif 1095 uno_Interface* pUnoI = bridge->map_cli2uno( 1096 proxy->m_cliI, demanded_td.get() ); 1097 uno_any_construct( 1098 (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 ); 1099 (*pUnoI->release)( pUnoI ); 1100 } 1101 else // object does not support demanded interface 1102 { 1103 uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 ); 1104 } 1105 // no excetpion occured 1106 *uno_exc = 0; 1107 } 1108 else 1109 { 1110 uno_any_construct( 1111 reinterpret_cast< uno_Any * >( uno_ret ), 1112 &pInterface, demanded_td.get(), 0 ); 1113 (*pInterface->release)( pInterface ); 1114 *uno_exc = 0; 1115 } 1116 break; 1117 } 1118 case 1: // acquire this proxy 1119 cli_proxy_acquire(proxy); 1120 *uno_exc = 0; 1121 break; 1122 case 2: // release this proxy 1123 cli_proxy_release(proxy); 1124 *uno_exc = 0; 1125 break; 1126 default: // arbitrary method call 1127 { 1128 typelib_InterfaceMethodTypeDescription * method_td = 1129 (typelib_InterfaceMethodTypeDescription *)member_td; 1130 OUString const& usMethodName= *(rtl_uString**) & 1131 ((typelib_InterfaceMemberTypeDescription*) member_td) 1132 ->pMemberName; 1133 1134 sr::MethodInfo* info = proxy->getMethodInfo(function_pos, 1135 usMethodName, CliProxy::MK_METHOD); 1136 bridge->call_cli( 1137 proxy->m_cliI, 1138 info, 1139 method_td->pReturnTypeRef, method_td->pParams, 1140 method_td->nParams, 1141 uno_ret, uno_args, uno_exc); 1142 return; 1143 } 1144 } 1145 break; 1146 } 1147 default: 1148 { 1149 throw BridgeRuntimeError( 1150 OUSTR("illegal member type description!") ); 1151 } 1152 } 1153 } 1154 catch (BridgeRuntimeError & err) 1155 { 1156 // binary identical struct 1157 ::com::sun::star::uno::RuntimeException exc( 1158 OUSTR("[cli_uno bridge error] ") + err.m_message, 1159 ::com::sun::star::uno::Reference< 1160 ::com::sun::star::uno::XInterface >() ); 1161 ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc); 1162 uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0); 1163 #if OSL_DEBUG_LEVEL >= 1 1164 OString cstr_msg(OUStringToOString(exc.Message, 1165 RTL_TEXTENCODING_ASCII_US ) ); 1166 OSL_ENSURE(0, cstr_msg.getStr()); 1167 #endif 1168 } 1169 } 1170 1171 1172 1173 1174 1175