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