merged tag ooo/DEV300_m102
[LibreOffice.git] / cli_ure / source / uno_bridge / cli_proxy.cxx
blob0fd662a24fe9e7308567d5b20a68cd21743e5229
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
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"
38 #using <mscorlib.dll>
39 #using <cli_ure.dll>
40 #using <cli_uretypes.dll>
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;
54 using namespace cli_uno;
55 using namespace rtl;
56 extern "C"
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();
76 namespace cli_uno
79 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
80 typelib_InterfaceTypeDescription* td):
82 m_unoI(unoI),
83 m_typeDesc(td),
84 m_bridge(bridge)
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)
92 typelib_TypeDescription* _pt = &m_typeDesc->aBase;
93 sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
94 if( ! bComplete)
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());
105 UnoInterfaceInfo::~UnoInterfaceInfo()
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();
112 m_unoI->release(m_unoI);
113 typelib_typedescription_release(
114 reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
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)
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);
142 UnoInterfaceProxy::~UnoInterfaceProxy()
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));
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();
159 System::Object* UnoInterfaceProxy::create(
160 Bridge * bridge,
161 uno_Interface * pUnoI,
162 typelib_InterfaceTypeDescription* pTD,
163 const OUString& oid)
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;
173 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
174 typelib_InterfaceTypeDescription* pTd)
176 sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator();
177 System::Threading::Monitor::Enter(this);
180 while (enumInfos->MoveNext())
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)))
196 return;
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
226 __finally {
227 System::Threading::Monitor::Exit(this);
232 // IRemotingTypeInfo
233 bool UnoInterfaceProxy::CanCastTo(System::Type* fromType,
234 System::Object*)
236 if (fromType == __typeof(System::Object)) // trivial case
237 return true;
239 System::Threading::Monitor::Enter(this);
242 if (0 != findInfo( fromType )) // proxy supports demanded interface
243 return true;
245 //query an uno interface for the required type
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];
256 args[0] = fromType;
257 __box uno::Any * pAny;
258 System::Object* pException = NULL;
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,
267 ((typelib_InterfaceMethodTypeDescription*)
268 membertd.get())->pParams,
269 args, NULL, &pException) );
271 // handle regular exception from target
272 OSL_ENSURE(
273 0 == pException,
274 OUStringToOString(
275 mapCliString( pException->ToString()),
276 RTL_TEXTENCODING_UTF8 ).getStr() );
278 if (pAny->Type != __typeof (void)) // has value?
280 if (0 != findInfo( fromType ))
282 // proxy now supports demanded interface
283 return true;
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 ))
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;
305 catch (BridgeRuntimeError& e)
307 (void) e; // avoid warning
308 OSL_ENSURE(
309 0, OUStringToOString(
310 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
312 catch (System::Exception* e)
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() );
323 catch (...)
325 OSL_ENSURE(
326 0, "An unexpected native C++ exception occurred in "
327 "UnoInterfaceProxy::CanCastTo()" );
329 __finally
331 System::Threading::Monitor::Exit(this);
333 return false;
336 srrm::IMessage* UnoInterfaceProxy::invokeObject(
337 sc::IDictionary* props,
338 srrm::LogicalCallContext* context,
339 srrm::IMethodCallMessage* mcm)
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))
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)
354 UnoInterfaceProxy* unoProxy =
355 dynamic_cast<UnoInterfaceProxy*>(rProxy);
356 if (unoProxy)
358 bool b = m_oid->Equals(unoProxy->getOid());
359 retMethod = __box(b);
360 bDone = true;
363 if (bDone == false)
365 //no proxy or not our proxy, therefore Equals must be false
366 retMethod = __box(false);
369 else if (m_GetHashCode_String->Equals(sMethod))
371 // Object.GetHashCode
372 int nHash = m_oid->GetHashCode();
373 retMethod = __box(nHash);
375 else if (m_GetType_String->Equals(sMethod))
377 // Object.GetType
378 retMethod = __typeof(System::Object);
380 else if (m_ToString_String->Equals(sMethod))
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();
389 else
391 //Either Object has new functions or a protected method was called
392 //which should not be possible
393 OSL_ASSERT(0);
395 srrm::IMessage* retVal= new srrm::ReturnMessage(
396 retMethod, new System::Object*[0], 0, context, mcm);
397 return retVal;
400 UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type )
402 for (int i = 0; i < m_numUnoIfaces; i++)
404 UnoInterfaceInfo* tmpInfo = static_cast<UnoInterfaceInfo*>(
405 m_listIfaces->get_Item(i));
406 if (type->IsAssignableFrom(tmpInfo->m_type))
407 return tmpInfo;
409 for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
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;
418 return 0;
421 srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg)
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);
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(','));
437 // Special Handling for System.Object methods
438 if(sTypeName->IndexOf(m_system_Object_String) != -1)
440 return invokeObject(props, context, mcm);
443 System::Type* typeBeingCalled = loadCliType(sTypeName);
444 UnoInterfaceInfo* info = findInfo( typeBeingCalled );
445 OSL_ASSERT( 0 != info );
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--; )
456 typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
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 );
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;
474 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
476 if ((usMethodName.getLength() == remainder
477 || (usMethodName.getLength() < remainder
478 && usTypeName[offset + usMethodName.getLength()] == ':'))
479 && usTypeName.match(usMethodName, offset))
481 TypeDescr member_td( member_type );
482 typelib_InterfaceMethodTypeDescription * method_td =
483 (typelib_InterfaceMethodTypeDescription *)
484 member_td.get();
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;
500 else
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)
516 if ('g' == usMethodName[0])
518 TypeDescr member_td( member_type );
519 typelib_InterfaceAttributeTypeDescription * attribute_td =
520 (typelib_InterfaceAttributeTypeDescription*)
521 member_td.get();
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);
532 else if ('s' == usMethodName[0])
534 TypeDescr member_td( member_type );
535 typelib_InterfaceAttributeTypeDescription * attribute_td =
536 (typelib_InterfaceAttributeTypeDescription *)
537 member_td.get();
538 if (! attribute_td->bReadOnly)
540 typelib_MethodParameter param;
541 param.pTypeRef = attribute_td->pAttributeTypeRef;
542 param.bIn = sal_True;
543 param.bOut = sal_False;
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, &param, args, NULL, &pExc);
553 return constructReturnMessage(NULL, NULL, NULL,
554 callmsg, pExc);
556 else
558 return constructReturnMessage(NULL, NULL, NULL,
559 callmsg, NULL);
562 break;
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() );
578 catch (BridgeRuntimeError & err)
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);
585 catch (System::Exception* e)
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);
600 catch (...)
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);
610 return NULL;
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.
616 srrm::IMessage* UnoInterfaceProxy::constructReturnMessage(
617 System::Object* cliReturn,
618 System::Object* args[],
619 typelib_InterfaceMethodTypeDescription* mtd,
620 srrm::IMessage* msg, System::Object* exc)
622 srrm::IMessage * retVal= NULL;
623 srrm::IMethodCallMessage* mcm = static_cast<srrm::IMethodCallMessage*>(msg);
624 if (exc)
626 retVal = new srrm::ReturnMessage(
627 dynamic_cast<System::Exception*>(exc), mcm);
629 else
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)
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++)
643 if (mtd->pParams[i].bOut)
645 arOut[i]= args[i];
646 nOut++;
649 retVal= new srrm::ReturnMessage(cliReturn, arOut, nOut,
650 context, mcm);
652 else
654 // Attribute (getXXX)
655 retVal= new srrm::ReturnMessage(cliReturn, NULL, 0,
656 context, mcm);
659 return retVal;
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)
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;
679 m_unoType.makeComplete();
680 m_type= mapUnoType(m_unoType.get());
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
691 void CliProxy::makeMethodInfos()
693 #if OSL_DEBUG_LEVEL >= 2
694 System::Object* cliI;
695 System::Type* type;
696 cliI = m_cliI;
697 type = m_type;
698 #endif
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++)
714 numMethods += arInheritedIfaces[i]->GetMethods()->get_Length();
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;
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
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();
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--)
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++)
758 m_arMethodInfos[index] = __try_cast<sr::MethodInfo*>(
759 mapInherited.TargetMethods[i]);
761 m_arInterfaceMethodInfos[index] = __try_cast<sr::MethodInfo*>(
762 mapInherited.InterfaceMethods[i]);
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++)
771 m_arMethodInfos[index]= __try_cast<sr::MethodInfo*>(
772 map.TargetMethods[i]);
773 m_arInterfaceMethodInfos[index]= __try_cast<sr::MethodInfo*>(
774 map.InterfaceMethods[i]);
777 catch (System::InvalidCastException* )
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() );
789 sr::MethodInfo* CliProxy::getMethodInfo(int nUnoFunctionPos,
790 const rtl::OUString& usMethodName, MethodKind methodKind)
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);
810 int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos];
811 if (cliPos != -1)
812 return m_arMethodInfos[cliPos];
814 //create the method function name
815 System::String* sMethodName = mapUnoString(usMethodName.pData);
816 switch (methodKind)
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);
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
844 int cMethods = m_arInterfaceMethodInfos->get_Length();
845 for (int i = 0; i < cMethods; i++)
847 System::String* cliMethod = m_arInterfaceMethodInfos[i]->Name;
848 if (cliMethod->Equals(sMethodName))
850 indexCliMethod = i;
851 break;
855 if (indexCliMethod == -1)
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;
865 m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
866 ret = m_arMethodInfos[indexCliMethod];
868 __finally
870 System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
873 return ret;
876 CliProxy::~CliProxy()
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();
889 uno_Interface* CliProxy::create(Bridge const * bridge,
890 System::Object* cliI,
891 typelib_TypeDescription const* pTD,
892 const rtl::OUString& ousOid)
894 uno_Interface* proxy= static_cast<uno_Interface*>(
895 new CliProxy(bridge, cliI, pTD, ousOid));
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)));
907 return proxy;
912 void SAL_CALL CliProxy::uno_DispatchMethod(
913 struct _uno_Interface *,
914 const struct _typelib_TypeDescription *,
915 void *,
916 void **,
917 uno_Any ** )
920 inline void CliProxy::acquire() const
922 if (1 == osl_incrementInterlockedCount( &m_ref ))
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
936 //---------------------------------------------------------------------------
937 inline void CliProxy::release() const
939 if (0 == osl_decrementInterlockedCount( &m_ref ))
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 ) );
955 extern "C"
956 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
957 SAL_THROW_EXTERN_C()
959 cli_uno::CliProxy * cliProxy = reinterpret_cast<
960 cli_uno::CliProxy * >( proxy );
962 delete cliProxy;
965 extern "C"
966 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
967 SAL_THROW_EXTERN_C()
969 CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
970 cliProxy->acquire();
972 //-----------------------------------------------------------------------------
973 extern "C"
974 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
975 SAL_THROW_EXTERN_C()
977 CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
978 cliProxy->release();
981 //------------------------------------------------------------------------------
982 extern "C"
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()
989 CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
992 Bridge const* bridge = proxy->m_bridge;
994 switch (member_td->eTypeClass)
996 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
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!" );
1012 if (uno_ret) // is getter method
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 );
1027 else // is setter method
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;
1041 bridge->call_cli(
1042 proxy->m_cliI,
1043 // set follows get method
1044 info,
1045 0 /* indicates void return */, &param, 1,
1046 0, uno_args, uno_exc );
1048 break;
1050 case typelib_TypeClass_INTERFACE_METHOD:
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!" );
1065 switch (function_pos)
1067 case 0: // queryInterface()
1069 TypeDescr demanded_td(
1070 *reinterpret_cast<typelib_TypeDescriptionReference **>(
1071 uno_args[0]));
1072 if (typelib_TypeClass_INTERFACE
1073 != demanded_td.get()->eTypeClass)
1075 throw BridgeRuntimeError(
1076 OUSTR("queryInterface() call demands an INTERFACE type!"));
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() );
1085 if (0 == pInterface)
1087 System::Type* mgdDemandedType =
1088 mapUnoType(demanded_td.get());
1089 if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
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 );
1105 else // object does not support demanded interface
1107 uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
1109 // no excetpion occured
1110 *uno_exc = 0;
1112 else
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;
1120 break;
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
1132 typelib_InterfaceMethodTypeDescription * method_td =
1133 (typelib_InterfaceMethodTypeDescription *)member_td;
1134 OUString const& usMethodName= *(rtl_uString**) &
1135 ((typelib_InterfaceMemberTypeDescription*) member_td)
1136 ->pMemberName;
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;
1149 break;
1151 default:
1153 throw BridgeRuntimeError(
1154 OUSTR("illegal member type description!") );
1158 catch (BridgeRuntimeError & err)
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