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