Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / cli_ure / source / uno_bridge / cli_proxy.cxx
blobfdcb20ad10a3ca6a1d85b0e832ebb864ec137e89
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "typelib/typedescription.h"
30 #include "rtl/ustrbuf.hxx"
31 #include "com/sun/star/uno/RuntimeException.hpp"
32 #include "osl/mutex.hxx"
33 #include "cli_proxy.h"
34 #include "cli_base.h"
35 #include "cli_bridge.h"
37 #using <mscorlib.dll>
38 #using <cli_ure.dll>
39 #using <cli_uretypes.dll>
41 namespace sr = System::Reflection;
42 namespace st = System::Text;
43 namespace sc = System::Collections;
44 namespace srrm = System::Runtime::Remoting::Messaging;
45 namespace srr = System::Runtime::Remoting;
46 namespace srrp = System::Runtime::Remoting::Proxies;
47 namespace sd = System::Diagnostics;
48 namespace css = com::sun::star;
49 namespace ucss = unoidl::com::sun::star;
51 using namespace cli_uno;
53 using ::rtl::OUString;
54 using ::rtl::OUStringToOString;
55 using ::rtl::OString;
56 using ::rtl::OUStringBuffer;
57 extern "C"
59 //------------------------------------------------------------------------------
60 void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy )
61 SAL_THROW_EXTERN_C();
62 //------------------------------------------------------------------------------
63 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
64 SAL_THROW_EXTERN_C();
65 //------------------------------------------------------------------------------
66 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
67 SAL_THROW_EXTERN_C();
68 //------------------------------------------------------------------------------
69 void SAL_CALL cli_proxy_dispatch(
70 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
71 void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
72 SAL_THROW_EXTERN_C();
77 namespace cli_uno
80 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
81 typelib_InterfaceTypeDescription* td):
83 m_unoI(unoI),
84 m_typeDesc(td),
85 m_bridge(bridge)
87 m_bridge->acquire();
88 m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td));
89 m_unoI->acquire(m_unoI);
90 typelib_typedescription_acquire(&m_typeDesc->aBase);
91 if ( ! m_typeDesc->aBase.bComplete)
93 typelib_TypeDescription* _pt = &m_typeDesc->aBase;
94 sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
95 if( ! bComplete)
97 OUStringBuffer buf( 128 );
98 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
99 "cannot make type complete: ") );
100 buf.append( *reinterpret_cast< OUString const * >(
101 & m_typeDesc->aBase.pTypeName));
102 throw BridgeRuntimeError(buf.makeStringAndClear());
106 UnoInterfaceInfo::~UnoInterfaceInfo()
108 //accessing unmanaged objects is ok.
109 m_bridge->m_uno_env->revokeInterface(
110 m_bridge->m_uno_env, m_unoI );
111 m_bridge->release();
113 m_unoI->release(m_unoI);
114 typelib_typedescription_release(
115 reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
118 UnoInterfaceProxy::UnoInterfaceProxy(
119 Bridge * bridge,
120 uno_Interface * pUnoI,
121 typelib_InterfaceTypeDescription* pTD,
122 const OUString& oid )
123 :RealProxy(__typeof(MarshalByRefObject)),
124 m_bridge(bridge),
125 m_oid(mapUnoString(oid.pData)),
126 m_sTypeName(m_system_Object_String)
128 m_bridge->acquire();
129 // create the list that holds all UnoInterfaceInfos
130 m_listIfaces = new ArrayList(10);
131 m_numUnoIfaces = 0;
132 m_listAdditionalProxies = new ArrayList();
133 m_nlistAdditionalProxies = 0;
134 //put the information of the first UNO interface into the arraylist
135 #if OSL_DEBUG_LEVEL >= 2
136 _numInterfaces = 0;
137 _sInterfaces = NULL;
138 #endif
139 addUnoInterface(pUnoI, pTD);
143 UnoInterfaceProxy::~UnoInterfaceProxy()
145 #if OSL_DEBUG_LEVEL >= 2
146 sd::Trace::WriteLine(System::String::Format(
147 new System::String(S"cli uno bridge: Destroying proxy "
148 S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "),
149 m_oid));
151 sd::Trace::WriteLine( mapUnoString(_sInterfaces));
152 rtl_uString_release(_sInterfaces);
153 #endif
154 //m_bridge is unmanaged, therefore we can access it in this finalizer
155 CliEnvHolder::g_cli_env->revokeInterface(m_oid);
156 m_bridge->release();
160 System::Object* UnoInterfaceProxy::create(
161 Bridge * bridge,
162 uno_Interface * pUnoI,
163 typelib_InterfaceTypeDescription* pTD,
164 const OUString& oid)
166 UnoInterfaceProxy* proxyHandler=
167 new UnoInterfaceProxy(bridge, pUnoI, pTD, oid);
168 System::Object* proxy= proxyHandler->GetTransparentProxy();
169 CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData));
170 return proxy;
174 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
175 typelib_InterfaceTypeDescription* pTd)
177 sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator();
178 System::Threading::Monitor::Enter(this);
181 while (enumInfos->MoveNext())
183 UnoInterfaceInfo* info = static_cast<UnoInterfaceInfo*>(
184 enumInfos->Current);
185 #if OSL_DEBUG_LEVEL > 1
186 System::Type * t1;
187 System::Type * t2;
188 t1 = mapUnoType(
189 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) );
190 t2 = mapUnoType(
191 reinterpret_cast<typelib_TypeDescription*>(pTd) );
192 #endif
193 if (typelib_typedescription_equals(
194 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc),
195 reinterpret_cast<typelib_TypeDescription*>(pTd)))
197 return;
200 OUString oid(mapCliString(m_oid));
201 (*m_bridge->m_uno_env->registerInterface)(
202 m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
203 oid.pData, pTd);
204 //This proxy does not contain the uno_Interface. Add it.
205 m_listIfaces->Add(new UnoInterfaceInfo(m_bridge, pUnoI, pTd));
206 m_numUnoIfaces = m_listIfaces->Count;
207 #if OSL_DEBUG_LEVEL >= 2
208 System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>(
209 m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName;
210 sd::Trace::WriteLine(System::String::Format(
211 new System::String(S"cli uno bridge: Creating proxy for uno object, "
212 S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName));
213 // add to the string that contains all interface names
214 _numInterfaces ++;
215 OUStringBuffer buf(512);
216 buf.appendAscii("\t");
217 buf.append( OUString::valueOf((sal_Int32)_numInterfaces));
218 buf.appendAscii(". ");
219 buf.append(mapCliString(sInterfaceName));
220 buf.appendAscii("\n");
221 OUString _sNewInterface = buf.makeStringAndClear();
222 rtl_uString * __pin * pp_sInterfaces = & _sInterfaces;
223 rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces,
224 _sNewInterface.pData);
225 #endif
227 __finally {
228 System::Threading::Monitor::Exit(this);
233 // IRemotingTypeInfo
234 bool UnoInterfaceProxy::CanCastTo(System::Type* fromType,
235 System::Object*)
237 if (fromType == __typeof(System::Object)) // trivial case
238 return true;
240 System::Threading::Monitor::Enter(this);
243 if (0 != findInfo( fromType )) // proxy supports demanded interface
244 return true;
246 //query an uno interface for the required type
248 // we use the first interface in the list (m_listIfaces) to make
249 // the queryInterface call
250 UnoInterfaceInfo* info =
251 static_cast<UnoInterfaceInfo*>(m_listIfaces->get_Item(0));
252 css::uno::TypeDescription membertd(
253 reinterpret_cast<typelib_InterfaceTypeDescription*>(
254 info->m_typeDesc)->ppAllMembers[0]);
255 System::Object *args[] = new System::Object*[1];
257 args[0] = fromType;
258 __box uno::Any * pAny;
259 System::Object* pException = NULL;
261 pAny= static_cast<__box uno::Any *>(
262 m_bridge->call_uno(
263 info->m_unoI,
264 membertd.get(),
265 ((typelib_InterfaceMethodTypeDescription*)
266 membertd.get())->pReturnTypeRef,
268 ((typelib_InterfaceMethodTypeDescription*)
269 membertd.get())->pParams,
270 args, NULL, &pException) );
272 // handle regular exception from target
273 OSL_ENSURE(
274 0 == pException,
275 OUStringToOString(
276 mapCliString( pException->ToString()),
277 RTL_TEXTENCODING_UTF8 ).getStr() );
279 if (pAny->Type != __typeof (void)) // has value?
281 if (0 != findInfo( fromType ))
283 // proxy now supports demanded interface
284 return true;
287 // via aggregation: it is possible that queryInterface() returns
288 // and interface with a different oid.
289 // That way, this type is supported for the CLI
290 // interpreter (CanCastTo() returns true)
291 ::System::Object * obj = pAny->Value;
292 OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) );
293 if (srr::RemotingServices::IsTransparentProxy( obj ))
295 UnoInterfaceProxy * proxy =
296 static_cast< UnoInterfaceProxy * >(
297 srr::RemotingServices::GetRealProxy( obj ) );
298 OSL_ASSERT( 0 != proxy->findInfo( fromType ) );
299 m_listAdditionalProxies->Add( proxy );
300 m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
301 OSL_ASSERT( 0 != findInfo( fromType ) );
302 return true;
306 catch (BridgeRuntimeError& e)
308 (void) e; // avoid warning
309 OSL_FAIL(
310 OUStringToOString(
311 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
313 catch (System::Exception* e)
315 System::String* msg= new System::String(
316 S"An unexpected CLI exception occurred in "
317 S"UnoInterfaceProxy::CanCastTo(). Original"
318 S"message: \n");
319 msg= System::String::Concat(msg, e->get_Message());
320 OSL_FAIL(
321 OUStringToOString(
322 mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() );
324 catch (...)
326 OSL_FAIL(
327 "An unexpected native C++ exception occurred in "
328 "UnoInterfaceProxy::CanCastTo()" );
330 __finally
332 System::Threading::Monitor::Exit(this);
334 return false;
337 srrm::IMessage* UnoInterfaceProxy::invokeObject(
338 sc::IDictionary* props,
339 srrm::LogicalCallContext* context,
340 srrm::IMethodCallMessage* mcm)
342 System::Object* retMethod = 0;
343 System::String* sMethod = static_cast<System::String*>
344 (props->get_Item(m_methodNameString));
345 System::Object* args[] = static_cast<System::Object*[]>(
346 props->get_Item(m_ArgsString));
347 if (m_Equals_String->Equals(sMethod))
349 // Object.Equals
350 OSL_ASSERT(args->get_Length() == 1);
351 srrp::RealProxy* rProxy = srr::RemotingServices::GetRealProxy(args[0]);
352 bool bDone = false;
353 if (rProxy)
355 UnoInterfaceProxy* unoProxy =
356 dynamic_cast<UnoInterfaceProxy*>(rProxy);
357 if (unoProxy)
359 bool b = m_oid->Equals(unoProxy->getOid());
360 retMethod = __box(b);
361 bDone = true;
364 if (bDone == false)
366 //no proxy or not our proxy, therefore Equals must be false
367 retMethod = __box(false);
370 else if (m_GetHashCode_String->Equals(sMethod))
372 // Object.GetHashCode
373 int nHash = m_oid->GetHashCode();
374 retMethod = __box(nHash);
376 else if (m_GetType_String->Equals(sMethod))
378 // Object.GetType
379 retMethod = __typeof(System::Object);
381 else if (m_ToString_String->Equals(sMethod))
383 // Object.ToString
384 st::StringBuilder* sb = new st::StringBuilder(256);
385 // sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}"
386 // S". OID: {1}", m_type->ToString(), m_oid);
387 sb->AppendFormat(S"Uno object proxy. OID: {0}", m_oid);
388 retMethod = sb->ToString();
390 else
392 //Either Object has new functions or a protected method was called
393 //which should not be possible
394 OSL_ASSERT(0);
396 srrm::IMessage* retVal= new srrm::ReturnMessage(
397 retMethod, new System::Object*[0], 0, context, mcm);
398 return retVal;
401 UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type )
403 for (int i = 0; i < m_numUnoIfaces; i++)
405 UnoInterfaceInfo* tmpInfo = static_cast<UnoInterfaceInfo*>(
406 m_listIfaces->get_Item(i));
407 if (type->IsAssignableFrom(tmpInfo->m_type))
408 return tmpInfo;
410 for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
412 UnoInterfaceProxy * proxy =
413 static_cast< UnoInterfaceProxy * >(
414 m_listAdditionalProxies->get_Item( i ) );
415 UnoInterfaceInfo * info = proxy->findInfo( type );
416 if (0 != info)
417 return info;
419 return 0;
422 srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg)
426 sc::IDictionary* props= callmsg->Properties;
427 srrm::LogicalCallContext* context=
428 static_cast<srrm::LogicalCallContext*>(
429 props->get_Item(m_CallContextString));
430 srrm::IMethodCallMessage* mcm=
431 static_cast<srrm::IMethodCallMessage*>(callmsg);
433 //Find out which UNO interface is being called
434 System::String* sTypeName = static_cast<System::String*>(
435 props->get_Item(m_typeNameString));
436 sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(','));
438 // Special Handling for System.Object methods
439 if(sTypeName->IndexOf(m_system_Object_String) != -1)
441 return invokeObject(props, context, mcm);
444 System::Type* typeBeingCalled = loadCliType(sTypeName);
445 UnoInterfaceInfo* info = findInfo( typeBeingCalled );
446 OSL_ASSERT( 0 != info );
448 // ToDo do without string conversion, a OUString is not needed here
449 // get the type description of the call
450 OUString usMethodName(mapCliString(static_cast<System::String*>(
451 props->get_Item(m_methodNameString))));
452 typelib_TypeDescriptionReference ** ppAllMembers =
453 info->m_typeDesc->ppAllMembers;
454 sal_Int32 numberMembers = info->m_typeDesc->nAllMembers;
455 for ( sal_Int32 nPos = numberMembers; nPos--; )
457 typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
459 // check usMethodName against fully qualified usTypeName
460 // of member_type; usTypeName is of the form
461 // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>)
462 OUString const & usTypeName =
463 OUString::unacquired( & member_type->pTypeName );
465 #if OSL_DEBUG_LEVEL >= 2
466 System::String * pTypeName;
467 pTypeName = mapUnoString(usTypeName.pData);
468 #endif
469 sal_Int32 offset = usTypeName.indexOf( ':' ) + 2;
470 OSL_ASSERT(
471 offset >= 2 && offset < usTypeName.getLength()
472 && usTypeName[offset - 1] == ':' );
473 sal_Int32 remainder = usTypeName.getLength() - offset;
475 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
477 if ((usMethodName.getLength() == remainder
478 || (usMethodName.getLength() < remainder
479 && usTypeName[offset + usMethodName.getLength()] == ':'))
480 && usTypeName.match(usMethodName, offset))
482 TypeDescr member_td( member_type );
483 typelib_InterfaceMethodTypeDescription * method_td =
484 (typelib_InterfaceMethodTypeDescription *)
485 member_td.get();
487 System::Object* args[] = static_cast<System::Object*[]>(
488 props->get_Item(m_ArgsString));
489 System::Type* argTypes[] = static_cast<System::Type*[]>(
490 props->get_Item(m_methodSignatureString));
491 System::Object* pExc = NULL;
492 System::Object * cli_ret = m_bridge->call_uno(
493 info->m_unoI, member_td.get(),
494 method_td->pReturnTypeRef, method_td->nParams,
495 method_td->pParams, args, argTypes, &pExc);
496 return constructReturnMessage(cli_ret, args, method_td,
497 callmsg, pExc);
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());
864 m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
865 ret = m_arMethodInfos[indexCliMethod];
867 __finally
869 System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
872 return ret;
875 CliProxy::~CliProxy()
877 #if OSL_DEBUG_LEVEL >= 2
878 sd::Trace::WriteLine(System::String::Format(
879 new System::String(
880 S"cli uno bridge: Destroying proxy for cli object, "
881 S"id:\n\t{0}\n\t{1}\n"),
882 m_oid, m_type));
883 #endif
884 CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get()));
885 m_bridge->release();
888 uno_Interface* CliProxy::create(Bridge const * bridge,
889 System::Object* cliI,
890 typelib_TypeDescription const* pTD,
891 const rtl::OUString& ousOid)
893 uno_Interface* proxy= static_cast<uno_Interface*>(
894 new CliProxy(bridge, cliI, pTD, ousOid));
896 //register proxy with target environment (uno)
897 (*bridge->m_uno_env->registerProxyInterface)(
898 bridge->m_uno_env,
899 reinterpret_cast<void**>(&proxy),
900 cli_proxy_free,
901 ousOid.pData, (typelib_InterfaceTypeDescription*) pTD);
902 //register original interface
903 CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData),
904 mapUnoType((pTD)));
906 return proxy;
911 void SAL_CALL CliProxy::uno_DispatchMethod(
912 struct _uno_Interface *,
913 const struct _typelib_TypeDescription *,
914 void *,
915 void **,
916 uno_Any ** )
919 inline void CliProxy::acquire() const
921 if (1 == osl_incrementInterlockedCount( &m_ref ))
923 // rebirth of proxy zombie
924 void * that = const_cast< CliProxy * >( this );
925 // register at uno env
926 (*m_bridge->m_uno_env->registerProxyInterface)(
927 m_bridge->m_uno_env, &that,
928 cli_proxy_free, m_usOid.pData,
929 (typelib_InterfaceTypeDescription *)m_unoType.get() );
930 #if OSL_DEBUG_LEVEL >= 2
931 OSL_ASSERT( this == (void const * const)that );
932 #endif
935 //---------------------------------------------------------------------------
936 inline void CliProxy::release() const
938 if (0 == osl_decrementInterlockedCount( &m_ref ))
940 // revoke from uno env on last release,
941 // The proxy can be resurrected if acquire is called before the uno
942 // environment calls cli_proxy_free. cli_proxy_free will
943 //delete the proxy. The environment does not acquire a registered
944 //proxy.
945 (*m_bridge->m_uno_env->revokeInterface)(
946 m_bridge->m_uno_env, const_cast< CliProxy * >( this ) );
954 extern "C"
955 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
956 SAL_THROW_EXTERN_C()
958 cli_uno::CliProxy * cliProxy = reinterpret_cast<
959 cli_uno::CliProxy * >( proxy );
961 delete cliProxy;
964 extern "C"
965 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
966 SAL_THROW_EXTERN_C()
968 CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
969 cliProxy->acquire();
971 //-----------------------------------------------------------------------------
972 extern "C"
973 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
974 SAL_THROW_EXTERN_C()
976 CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
977 cliProxy->release();
980 //------------------------------------------------------------------------------
981 extern "C"
983 void SAL_CALL cli_proxy_dispatch(
984 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
985 void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
986 SAL_THROW_EXTERN_C()
988 CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
991 Bridge const* bridge = proxy->m_bridge;
993 switch (member_td->eTypeClass)
995 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
998 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
999 member_td)->nPosition;
1000 typelib_InterfaceTypeDescription * iface_td =
1001 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
1002 OSL_ENSURE(
1003 member_pos < iface_td->nAllMembers,
1004 "### member pos out of range!" );
1005 sal_Int32 function_pos =
1006 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
1007 OSL_ENSURE(
1008 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
1009 "### illegal function index!" );
1011 if (uno_ret) // is getter method
1013 OUString const& usAttrName= *(rtl_uString**)&
1014 ((typelib_InterfaceMemberTypeDescription*) member_td)
1015 ->pMemberName;
1016 sr::MethodInfo* info = proxy->getMethodInfo(function_pos,
1017 usAttrName, CliProxy::MK_GET);
1018 bridge->call_cli(
1019 proxy->m_cliI,
1020 info,
1021 ((typelib_InterfaceAttributeTypeDescription *)member_td)
1022 ->pAttributeTypeRef,
1023 0, 0, // no params
1024 uno_ret, 0, uno_exc );
1026 else // is setter method
1028 OUString const& usAttrName= *(rtl_uString**) &
1029 ((typelib_InterfaceMemberTypeDescription*) member_td)
1030 ->pMemberName;
1031 sr::MethodInfo* info = proxy->getMethodInfo(function_pos + 1,
1032 usAttrName, CliProxy::MK_SET);
1033 typelib_MethodParameter param;
1034 param.pTypeRef =
1035 ((typelib_InterfaceAttributeTypeDescription *)member_td)
1036 ->pAttributeTypeRef;
1037 param.bIn = sal_True;
1038 param.bOut = sal_False;
1040 bridge->call_cli(
1041 proxy->m_cliI,
1042 // set follows get method
1043 info,
1044 0 /* indicates void return */, &param, 1,
1045 0, uno_args, uno_exc );
1047 break;
1049 case typelib_TypeClass_INTERFACE_METHOD:
1051 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
1052 member_td)->nPosition;
1053 typelib_InterfaceTypeDescription * iface_td =
1054 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
1055 OSL_ENSURE(
1056 member_pos < iface_td->nAllMembers,
1057 "### member pos out of range!" );
1058 sal_Int32 function_pos =
1059 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
1060 OSL_ENSURE(
1061 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
1062 "### illegal function index!" );
1064 switch (function_pos)
1066 case 0: // queryInterface()
1068 TypeDescr demanded_td(
1069 *reinterpret_cast<typelib_TypeDescriptionReference **>(
1070 uno_args[0]));
1071 if (typelib_TypeClass_INTERFACE
1072 != demanded_td.get()->eTypeClass)
1074 throw BridgeRuntimeError(
1075 OUSTR("queryInterface() call demands an INTERFACE type!"));
1078 uno_Interface * pInterface = 0;
1079 (*bridge->m_uno_env->getRegisteredInterface)(
1080 bridge->m_uno_env,
1081 (void **)&pInterface, proxy->m_usOid.pData,
1082 (typelib_InterfaceTypeDescription *)demanded_td.get() );
1084 if (0 == pInterface)
1086 System::Type* mgdDemandedType =
1087 mapUnoType(demanded_td.get());
1088 if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
1090 #if OSL_DEBUG_LEVEL > 0
1091 OUString usOid(
1092 mapCliString(
1093 CliEnvHolder::g_cli_env->getObjectIdentifier(
1094 proxy->m_cliI )));
1095 OSL_ENSURE(usOid.equals( proxy->m_usOid ),
1096 "### different oids!");
1097 #endif
1098 uno_Interface* pUnoI = bridge->map_cli2uno(
1099 proxy->m_cliI, demanded_td.get() );
1100 uno_any_construct(
1101 (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 );
1102 (*pUnoI->release)( pUnoI );
1104 else // object does not support demanded interface
1106 uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
1108 // no excetpion occurred
1109 *uno_exc = 0;
1111 else
1113 uno_any_construct(
1114 reinterpret_cast< uno_Any * >( uno_ret ),
1115 &pInterface, demanded_td.get(), 0 );
1116 (*pInterface->release)( pInterface );
1117 *uno_exc = 0;
1119 break;
1121 case 1: // acquire this proxy
1122 cli_proxy_acquire(proxy);
1123 *uno_exc = 0;
1124 break;
1125 case 2: // release this proxy
1126 cli_proxy_release(proxy);
1127 *uno_exc = 0;
1128 break;
1129 default: // arbitrary method call
1131 typelib_InterfaceMethodTypeDescription * method_td =
1132 (typelib_InterfaceMethodTypeDescription *)member_td;
1133 OUString const& usMethodName= *(rtl_uString**) &
1134 ((typelib_InterfaceMemberTypeDescription*) member_td)
1135 ->pMemberName;
1137 sr::MethodInfo* info = proxy->getMethodInfo(function_pos,
1138 usMethodName, CliProxy::MK_METHOD);
1139 bridge->call_cli(
1140 proxy->m_cliI,
1141 info,
1142 method_td->pReturnTypeRef, method_td->pParams,
1143 method_td->nParams,
1144 uno_ret, uno_args, uno_exc);
1145 return;
1148 break;
1150 default:
1152 throw BridgeRuntimeError(
1153 OUSTR("illegal member type description!") );
1157 catch (BridgeRuntimeError & err)
1159 // binary identical struct
1160 ::com::sun::star::uno::RuntimeException exc(
1161 OUSTR("[cli_uno bridge error] ") + err.m_message,
1162 ::com::sun::star::uno::Reference<
1163 ::com::sun::star::uno::XInterface >() );
1164 ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc);
1165 uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0);
1166 #if OSL_DEBUG_LEVEL >= 1
1167 OString cstr_msg(OUStringToOString(exc.Message,
1168 RTL_TEXTENCODING_ASCII_US ) );
1169 OSL_FAIL(cstr_msg.getStr());
1170 #endif
1178 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */