Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / cli_ure / source / uno_bridge / cli_proxy.cxx
blob61c3036ee14db4dc3c77a24cc7672737370e16f9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "typelib/typedescription.h"
21 #include "rtl/ustrbuf.hxx"
22 #include "com/sun/star/uno/RuntimeException.hpp"
23 #include "osl/mutex.hxx"
24 #include "cli_proxy.h"
25 #include "cli_base.h"
26 #include "cli_bridge.h"
28 #using <cli_ure.dll>
29 #using <cli_uretypes.dll>
31 namespace sr = System::Reflection;
32 namespace st = System::Text;
33 namespace sc = System::Collections;
34 namespace srrm = System::Runtime::Remoting::Messaging;
35 namespace srr = System::Runtime::Remoting;
36 namespace srrp = System::Runtime::Remoting::Proxies;
37 namespace sd = System::Diagnostics;
38 namespace ucss = unoidl::com::sun::star;
40 using namespace cli_uno;
42 using ::rtl::OUString;
43 using ::rtl::OUStringToOString;
44 using ::rtl::OString;
45 using ::rtl::OUStringBuffer;
46 extern "C"
48 //------------------------------------------------------------------------------
49 void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy )
50 SAL_THROW_EXTERN_C();
51 //------------------------------------------------------------------------------
52 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
53 SAL_THROW_EXTERN_C();
54 //------------------------------------------------------------------------------
55 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
56 SAL_THROW_EXTERN_C();
57 //------------------------------------------------------------------------------
58 void SAL_CALL cli_proxy_dispatch(
59 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
60 void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
61 SAL_THROW_EXTERN_C();
66 namespace cli_uno
69 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
70 typelib_InterfaceTypeDescription* td):
72 m_unoI(unoI),
73 m_typeDesc(td),
74 m_bridge(bridge)
76 m_bridge->acquire();
77 m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td));
78 m_unoI->acquire(m_unoI);
79 typelib_typedescription_acquire(&m_typeDesc->aBase);
80 if ( ! m_typeDesc->aBase.bComplete)
82 typelib_TypeDescription* _pt = &m_typeDesc->aBase;
83 sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
84 if( ! bComplete)
86 OUStringBuffer buf( 128 );
87 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
88 "cannot make type complete: ") );
89 buf.append( *reinterpret_cast< OUString const * >(
90 & m_typeDesc->aBase.pTypeName));
91 throw BridgeRuntimeError(buf.makeStringAndClear());
95 UnoInterfaceInfo::~UnoInterfaceInfo()
97 //accessing unmanaged objects is ok.
98 m_bridge->m_uno_env->revokeInterface(
99 m_bridge->m_uno_env, m_unoI );
100 m_bridge->release();
102 m_unoI->release(m_unoI);
103 typelib_typedescription_release(
104 reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
107 UnoInterfaceProxy::UnoInterfaceProxy(
108 Bridge * bridge,
109 uno_Interface * pUnoI,
110 typelib_InterfaceTypeDescription* pTD,
111 const OUString& oid )
112 :RealProxy(MarshalByRefObject::typeid),
113 m_bridge(bridge),
114 m_oid(mapUnoString(oid.pData)),
115 m_sTypeName(m_system_Object_String)
117 m_bridge->acquire();
118 // create the list that holds all UnoInterfaceInfos
119 m_listIfaces = gcnew ArrayList(10);
120 m_numUnoIfaces = 0;
121 m_listAdditionalProxies = gcnew ArrayList();
122 m_nlistAdditionalProxies = 0;
123 //put the information of the first UNO interface into the arraylist
124 #if OSL_DEBUG_LEVEL >= 2
125 _numInterfaces = 0;
126 _sInterfaces = NULL;
127 #endif
128 addUnoInterface(pUnoI, pTD);
132 UnoInterfaceProxy::~UnoInterfaceProxy()
134 #if OSL_DEBUG_LEVEL >= 2
135 sd::Trace::WriteLine(System::String::Format(
136 new System::String(S"cli uno bridge: Destroying proxy "
137 S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "),
138 m_oid));
140 sd::Trace::WriteLine( mapUnoString(_sInterfaces));
141 rtl_uString_release(_sInterfaces);
142 #endif
143 //m_bridge is unmanaged, therefore we can access it in this finalizer
144 CliEnvHolder::g_cli_env->revokeInterface(m_oid);
145 m_bridge->release();
149 System::Object^ UnoInterfaceProxy::create(
150 Bridge * bridge,
151 uno_Interface * pUnoI,
152 typelib_InterfaceTypeDescription* pTD,
153 const OUString& oid)
155 UnoInterfaceProxy^ proxyHandler=
156 gcnew UnoInterfaceProxy(bridge, pUnoI, pTD, oid);
157 System::Object^ proxy= proxyHandler->GetTransparentProxy();
158 CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData));
159 return proxy;
163 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
164 typelib_InterfaceTypeDescription* pTd)
166 sc::IEnumerator^ enumInfos = m_listIfaces->GetEnumerator();
167 System::Threading::Monitor::Enter(this);
170 while (enumInfos->MoveNext())
172 UnoInterfaceInfo^ info = static_cast<UnoInterfaceInfo^>(
173 enumInfos->Current);
174 #if OSL_DEBUG_LEVEL > 1
175 System::Type * t1;
176 System::Type * t2;
177 t1 = mapUnoType(
178 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) );
179 t2 = mapUnoType(
180 reinterpret_cast<typelib_TypeDescription*>(pTd) );
181 #endif
182 if (typelib_typedescription_equals(
183 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc),
184 reinterpret_cast<typelib_TypeDescription*>(pTd)))
186 return;
189 OUString oid(mapCliString(m_oid));
190 (*m_bridge->m_uno_env->registerInterface)(
191 m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
192 oid.pData, pTd);
193 //This proxy does not contain the uno_Interface. Add it.
194 m_listIfaces->Add(gcnew UnoInterfaceInfo(m_bridge, pUnoI, pTd));
195 m_numUnoIfaces = m_listIfaces->Count;
196 #if OSL_DEBUG_LEVEL >= 2
197 System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>(
198 m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName;
199 sd::Trace::WriteLine(System::String::Format(
200 new System::String(S"cli uno bridge: Creating proxy for uno object, "
201 S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName));
202 // add to the string that contains all interface names
203 _numInterfaces ++;
204 OUStringBuffer buf(512);
205 buf.appendAscii("\t");
206 buf.append( OUString::valueOf((sal_Int32)_numInterfaces));
207 buf.appendAscii(". ");
208 buf.append(mapCliString(sInterfaceName));
209 buf.appendAscii("\n");
210 OUString _sNewInterface = buf.makeStringAndClear();
211 rtl_uString * __pin * pp_sInterfaces = & _sInterfaces;
212 rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces,
213 _sNewInterface.pData);
214 #endif
216 __finally {
217 System::Threading::Monitor::Exit(this);
222 // IRemotingTypeInfo
223 bool UnoInterfaceProxy::CanCastTo(System::Type^ fromType,
224 System::Object^)
226 if (fromType == System::Object::typeid) // trivial case
227 return true;
229 System::Threading::Monitor::Enter(this);
232 if (nullptr != findInfo( fromType )) // proxy supports demanded interface
233 return true;
235 //query an uno interface for the required type
237 // we use the first interface in the list (m_listIfaces) to make
238 // the queryInterface call
239 UnoInterfaceInfo^ info =
240 static_cast<UnoInterfaceInfo^>(m_listIfaces[0]);
241 css::uno::TypeDescription membertd(
242 reinterpret_cast<typelib_InterfaceTypeDescription*>(
243 info->m_typeDesc)->ppAllMembers[0]);
244 array<System::Object^>^ args = gcnew array<System::Object^>(1);
246 args[0] = fromType;
247 uno::Any ^ pAny;
248 System::Object^ pException = nullptr;
250 pAny= static_cast<uno::Any ^>(
251 m_bridge->call_uno(
252 info->m_unoI,
253 membertd.get(),
254 ((typelib_InterfaceMethodTypeDescription*)
255 membertd.get())->pReturnTypeRef,
257 ((typelib_InterfaceMethodTypeDescription*)
258 membertd.get())->pParams,
259 args, nullptr, &pException) );
261 // handle regular exception from target
262 OSL_ENSURE(
263 nullptr == pException,
264 OUStringToOString(
265 mapCliString( pException->ToString()),
266 RTL_TEXTENCODING_UTF8 ).getStr() );
268 if (pAny->Type != void::typeid) // has value?
270 if (nullptr != findInfo( fromType ))
272 // proxy now supports demanded interface
273 return true;
276 // via aggregation: it is possible that queryInterface() returns
277 // and interface with a different oid.
278 // That way, this type is supported for the CLI
279 // interpreter (CanCastTo() returns true)
280 ::System::Object ^ obj = pAny->Value;
281 OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) );
282 if (srr::RemotingServices::IsTransparentProxy( obj ))
284 UnoInterfaceProxy ^ proxy =
285 static_cast< UnoInterfaceProxy ^ >(
286 srr::RemotingServices::GetRealProxy( obj ) );
287 OSL_ASSERT( nullptr != proxy->findInfo( fromType ) );
288 m_listAdditionalProxies->Add( proxy );
289 m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
290 OSL_ASSERT( nullptr != findInfo( fromType ) );
291 return true;
295 catch (BridgeRuntimeError& e)
297 (void) e; // avoid warning
298 OSL_FAIL(
299 OUStringToOString(
300 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
302 catch (System::Exception^ e)
304 System::String^ msg= gcnew System::String(
305 "An unexpected CLI exception occurred in "
306 "UnoInterfaceProxy::CanCastTo(). Original"
307 "message: \n");
308 msg= System::String::Concat(msg, e->Message);
309 OSL_FAIL(
310 OUStringToOString(
311 mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() );
313 catch (...)
315 OSL_FAIL(
316 "An unexpected native C++ exception occurred in "
317 "UnoInterfaceProxy::CanCastTo()" );
319 __finally
321 System::Threading::Monitor::Exit(this);
323 return false;
326 srrm::IMessage^ UnoInterfaceProxy::invokeObject(
327 sc::IDictionary^ props,
328 srrm::LogicalCallContext^ context,
329 srrm::IMethodCallMessage^ mcm)
331 System::Object^ retMethod = nullptr;
332 System::String^ sMethod = static_cast<System::String^>
333 (props[m_methodNameString]);
334 array<System::Object^>^ args = static_cast<array<System::Object^>^>(
335 props[m_ArgsString]);
336 if (m_Equals_String->Equals(sMethod))
338 // Object.Equals
339 OSL_ASSERT(args->Length == 1);
340 srrp::RealProxy^ rProxy = srr::RemotingServices::GetRealProxy(args[0]);
341 bool bDone = false;
342 if (rProxy)
344 UnoInterfaceProxy^ unoProxy =
345 dynamic_cast<UnoInterfaceProxy^>(rProxy);
346 if (unoProxy)
348 bool b = m_oid->Equals(unoProxy->getOid());
349 retMethod = b;
350 bDone = true;
353 if (bDone == false)
355 //no proxy or not our proxy, therefore Equals must be false
356 retMethod = false;
359 else if (m_GetHashCode_String->Equals(sMethod))
361 // Object.GetHashCode
362 int nHash = m_oid->GetHashCode();
363 retMethod = nHash;
365 else if (m_GetType_String->Equals(sMethod))
367 // Object.GetType
368 retMethod = System::Object::typeid;
370 else if (m_ToString_String->Equals(sMethod))
372 // Object.ToString
373 st::StringBuilder^ sb = gcnew st::StringBuilder(256);
374 // sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}"
375 // S". OID: {1}", m_type->ToString(), m_oid);
376 sb->AppendFormat("Uno object proxy. OID: {0}", m_oid);
377 retMethod = sb->ToString();
379 else
381 //Either Object has new functions or a protected method was called
382 //which should not be possible
383 OSL_ASSERT(0);
385 srrm::IMessage^ retVal= gcnew srrm::ReturnMessage(
386 retMethod, gcnew array<System::Object^>(0), 0, context, mcm);
387 return retVal;
390 UnoInterfaceInfo ^ UnoInterfaceProxy::findInfo( ::System::Type ^ type )
392 for (int i = 0; i < m_numUnoIfaces; i++)
394 UnoInterfaceInfo^ tmpInfo = static_cast<UnoInterfaceInfo^>(
395 m_listIfaces[i]);
396 if (type->IsAssignableFrom(tmpInfo->m_type))
397 return tmpInfo;
399 for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
401 UnoInterfaceProxy ^ proxy =
402 static_cast< UnoInterfaceProxy ^ >(
403 m_listAdditionalProxies[ i ] );
404 UnoInterfaceInfo ^ info = proxy->findInfo( type );
405 if (nullptr != info)
406 return info;
408 return nullptr;
411 srrm::IMessage^ UnoInterfaceProxy::Invoke(srrm::IMessage^ callmsg)
415 sc::IDictionary^ props= callmsg->Properties;
416 srrm::LogicalCallContext^ context=
417 static_cast<srrm::LogicalCallContext^>(
418 props[m_CallContextString]);
419 srrm::IMethodCallMessage^ mcm=
420 static_cast<srrm::IMethodCallMessage^>(callmsg);
422 //Find out which UNO interface is being called
423 System::String^ sTypeName = static_cast<System::String^>(
424 props[m_typeNameString]);
425 sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(','));
427 // Special Handling for System.Object methods
428 if(sTypeName->IndexOf(m_system_Object_String) != -1)
430 return invokeObject(props, context, mcm);
433 System::Type^ typeBeingCalled = loadCliType(sTypeName);
434 UnoInterfaceInfo^ info = findInfo( typeBeingCalled );
435 OSL_ASSERT( nullptr != info );
437 // ToDo do without string conversion, a OUString is not needed here
438 // get the type description of the call
439 OUString usMethodName(mapCliString(static_cast<System::String^>(
440 props[m_methodNameString])));
441 typelib_TypeDescriptionReference ** ppAllMembers =
442 info->m_typeDesc->ppAllMembers;
443 sal_Int32 numberMembers = info->m_typeDesc->nAllMembers;
444 for ( sal_Int32 nPos = numberMembers; nPos--; )
446 typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
448 // check usMethodName against fully qualified usTypeName
449 // of member_type; usTypeName is of the form
450 // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>)
451 OUString const & usTypeName =
452 OUString::unacquired( & member_type->pTypeName );
454 #if OSL_DEBUG_LEVEL >= 2
455 System::String * pTypeName;
456 pTypeName = mapUnoString(usTypeName.pData);
457 #endif
458 sal_Int32 offset = usTypeName.indexOf( ':' ) + 2;
459 OSL_ASSERT(
460 offset >= 2 && offset < usTypeName.getLength()
461 && usTypeName[offset - 1] == ':' );
462 sal_Int32 remainder = usTypeName.getLength() - offset;
464 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
466 if ((usMethodName.getLength() == remainder
467 || (usMethodName.getLength() < remainder
468 && usTypeName[offset + usMethodName.getLength()] == ':'))
469 && usTypeName.match(usMethodName, offset))
471 TypeDescr member_td( member_type );
472 typelib_InterfaceMethodTypeDescription * method_td =
473 (typelib_InterfaceMethodTypeDescription *)
474 member_td.get();
476 array<System::Object^>^ args = static_cast<array<System::Object^>^>(
477 props[m_ArgsString]);
478 array<System::Type^>^ argTypes = static_cast<array<System::Type^>^>(
479 props[m_methodSignatureString]);
480 System::Object^ pExc = nullptr;
481 System::Object ^ cli_ret = m_bridge->call_uno(
482 info->m_unoI, member_td.get(),
483 method_td->pReturnTypeRef, method_td->nParams,
484 method_td->pParams, args, argTypes, &pExc);
485 return constructReturnMessage(cli_ret, args, method_td,
486 callmsg, pExc);
489 else
491 OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE ==
492 member_type->eTypeClass );
493 if (usMethodName.getLength() > 4
494 && (usMethodName.getLength() - 4 == remainder
495 || (usMethodName.getLength() - 4 < remainder
496 && usTypeName[
497 offset + (usMethodName.getLength() - 4)] == ':'))
498 && usMethodName[1] == 'e' && usMethodName[2] == 't'
499 && rtl_ustr_compare_WithLength(
500 usTypeName.getStr() + offset,
501 usMethodName.getLength() - 4,
502 usMethodName.getStr() + 4,
503 usMethodName.getLength() - 4) == 0)
505 if ('g' == usMethodName[0])
507 TypeDescr member_td( member_type );
508 typelib_InterfaceAttributeTypeDescription * attribute_td =
509 (typelib_InterfaceAttributeTypeDescription*)
510 member_td.get();
512 System::Object^ pExc = nullptr;
513 System::Object^ cli_ret= m_bridge->call_uno(
514 info->m_unoI, member_td.get(),
515 attribute_td->pAttributeTypeRef,
516 0, 0,
517 nullptr, nullptr, &pExc);
518 return constructReturnMessage(cli_ret, nullptr, NULL,
519 callmsg, pExc);
521 else if ('s' == usMethodName[0])
523 TypeDescr member_td( member_type );
524 typelib_InterfaceAttributeTypeDescription * attribute_td =
525 (typelib_InterfaceAttributeTypeDescription *)
526 member_td.get();
527 if (! attribute_td->bReadOnly)
529 typelib_MethodParameter param;
530 param.pTypeRef = attribute_td->pAttributeTypeRef;
531 param.bIn = sal_True;
532 param.bOut = sal_False;
534 array<System::Object^>^ args =
535 static_cast<array<System::Object^>^>(
536 props[m_ArgsString]);
537 System::Object^ pExc = nullptr;
538 m_bridge->call_uno(
539 info->m_unoI, member_td.get(),
540 ::getCppuVoidType().getTypeLibType(),
541 1, &param, args, nullptr, &pExc);
542 return constructReturnMessage(nullptr, nullptr, NULL,
543 callmsg, pExc);
545 else
547 return constructReturnMessage(nullptr, nullptr, NULL,
548 callmsg, nullptr);
551 break;
555 // ToDo check if the message of the exception is not crippled
556 // the thing that should not be... no method info found!
557 OUStringBuffer buf( 64 );
558 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
559 "[cli_uno bridge]calling undeclared function on "
560 "interface ") );
561 buf.append( *reinterpret_cast< OUString const * >(
562 & ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName));
563 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
564 buf.append( usMethodName );
565 throw BridgeRuntimeError( buf.makeStringAndClear() );
567 catch (BridgeRuntimeError & err)
569 srrm::IMethodCallMessage^ mcm =
570 static_cast<srrm::IMethodCallMessage^>(callmsg);
571 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
572 mapUnoString(err.m_message.pData), nullptr), mcm);
574 catch (System::Exception^ e)
576 st::StringBuilder ^ sb = gcnew st::StringBuilder(512);
577 sb->Append(gcnew System::String(
578 "An unexpected CLI exception occurred in "
579 "UnoInterfaceProxy::Invoke. Original"
580 "message: \n"));
581 sb->Append(e->Message);
582 sb->Append((__wchar_t) '\n');
583 sb->Append(e->StackTrace);
584 srrm::IMethodCallMessage^ mcm =
585 static_cast<srrm::IMethodCallMessage^>(callmsg);
586 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
587 sb->ToString(), nullptr), mcm);
589 catch (...)
591 System::String^ msg = gcnew System::String(
592 "An unexpected native C++ exception occurred in "
593 "UnoInterfaceProxy::Invoke.");
594 srrm::IMethodCallMessage^ mcm =
595 static_cast<srrm::IMethodCallMessage^>(callmsg);
596 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
597 msg, nullptr), mcm);
599 return nullptr;
601 /** If the argument args is NULL then this function is called for an attribute
602 method (either setXXX or getXXX).
603 For attributes the argument mtd is also NULL.
605 srrm::IMessage^ UnoInterfaceProxy::constructReturnMessage(
606 System::Object^ cliReturn,
607 array<System::Object^>^ args,
608 typelib_InterfaceMethodTypeDescription* mtd,
609 srrm::IMessage^ msg, System::Object^ exc)
611 srrm::IMessage ^ retVal= nullptr;
612 srrm::IMethodCallMessage^ mcm = static_cast<srrm::IMethodCallMessage^>(msg);
613 if (exc)
615 retVal = gcnew srrm::ReturnMessage(
616 dynamic_cast<System::Exception^>(exc), mcm);
618 else
620 sc::IDictionary^ props= msg->Properties;
621 srrm::LogicalCallContext^ context=
622 static_cast<srrm::LogicalCallContext^>(
623 props[m_CallContextString]);
624 if (args != nullptr)
626 // Method
627 //build the array of out parameters, allocate max length
628 array<System::Object^>^ arOut= gcnew array<System::Object^>(mtd->nParams);
629 int nOut = 0;
630 for (int i= 0; i < mtd->nParams; i++)
632 if (mtd->pParams[i].bOut)
634 arOut[i]= args[i];
635 nOut++;
638 retVal= gcnew srrm::ReturnMessage(cliReturn, arOut, nOut,
639 context, mcm);
641 else
643 // Attribute (getXXX)
644 retVal= gcnew srrm::ReturnMessage(cliReturn, nullptr, 0,
645 context, mcm);
648 return retVal;
651 //################################################################################
652 CliProxy::CliProxy(Bridge const* bridge, System::Object^ cliI,
653 typelib_TypeDescription const* td,
654 const rtl::OUString& usOid):
655 m_ref(1),
656 m_bridge(bridge),
657 m_cliI(cliI),
658 m_unoType(const_cast<typelib_TypeDescription*>(td)),
659 m_usOid(usOid),
660 m_oid(mapUnoString(usOid.pData)),
661 m_nInheritedInterfaces(0)
663 m_bridge->acquire();
664 uno_Interface::acquire = cli_proxy_acquire;
665 uno_Interface::release = cli_proxy_release;
666 uno_Interface::pDispatcher = cli_proxy_dispatch;
668 m_unoType.makeComplete();
669 m_type= mapUnoType(m_unoType.get());
671 makeMethodInfos();
672 #if OSL_DEBUG_LEVEL >= 2
673 sd::Trace::WriteLine(System::String::Format(
674 new System::String(S"cli uno bridge: Creating proxy for cli object, "
675 S"id:\n\t{0}\n\t{1}"), m_oid, m_type));
676 #endif
680 void CliProxy::makeMethodInfos()
682 #if OSL_DEBUG_LEVEL >= 2
683 System::Object* cliI;
684 System::Type* type;
685 cliI = m_cliI;
686 type = m_type;
687 #endif
689 if (m_type->IsInterface == false)
690 return;
691 array<sr::MethodInfo^>^ arThisMethods = m_type->GetMethods();
692 //get the inherited interfaces
693 array<System::Type^>^ arInheritedIfaces = m_type->GetInterfaces();
694 m_nInheritedInterfaces = arInheritedIfaces->Length;
695 //array containing the number of methods for the interface and its
696 //inherited interfaces
697 m_arInterfaceMethodCount = gcnew array<int^>(m_nInheritedInterfaces + 1);
698 //determine the number of all interface methods, including the inherited
699 //interfaces
700 int numMethods = arThisMethods->Length;
701 for (int i= 0; i < m_nInheritedInterfaces; i++)
703 numMethods += arInheritedIfaces[i]->GetMethods()->Length;
705 //array containing MethodInfos of the cli object
706 m_arMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
707 //array containing MethodInfos of the interface
708 m_arInterfaceMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
709 //array containing the mapping of Uno interface pos to pos in
710 //m_arMethodInfos
711 m_arUnoPosToCliPos = gcnew array<System::Int32>(numMethods);
712 // initialize with -1
713 for (int i = 0; i < numMethods; i++)
714 m_arUnoPosToCliPos[i] = -1;
716 #if OSL_DEBUG_LEVEL >= 2
717 sr::MethodInfo* arMethodInfosDbg[];
718 sr::MethodInfo* arInterfaceMethodInfosDbg[];
719 System::Int32 arInterfaceMethodCountDbg[];
720 arMethodInfosDbg = m_arMethodInfos;
721 arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos;
722 arInterfaceMethodCountDbg = m_arInterfaceMethodCount;
723 #endif
726 //fill m_arMethodInfos with the mappings
727 // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
728 // to documentation
729 // but it is Type*[] instead. Bug in the framework?
730 System::Type^ objType = m_cliI->GetType();
733 int index = 0;
734 // now get the methods from the inherited interface
735 //arInheritedIfaces[0] is the direct base interface
736 //arInheritedIfaces[n] is the furthest inherited interface
737 //Start with the base interface
738 int nArLength = arInheritedIfaces->Length;
739 for (;nArLength > 0; nArLength--)
741 sr::InterfaceMapping mapInherited = objType->GetInterfaceMap(
742 arInheritedIfaces[nArLength - 1]);
743 int numMethods = mapInherited.TargetMethods->Length;
744 m_arInterfaceMethodCount[nArLength - 1] = numMethods;
745 for (int i = 0; i < numMethods; i++, index++)
747 m_arMethodInfos[index] = safe_cast<sr::MethodInfo^>(
748 mapInherited.TargetMethods[i]);
750 m_arInterfaceMethodInfos[index] = safe_cast<sr::MethodInfo^>(
751 mapInherited.InterfaceMethods[i]);
754 //At last come the methods of the furthest derived interface
755 sr::InterfaceMapping map = objType->GetInterfaceMap(m_type);
756 nArLength = map.TargetMethods->Length;
757 m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength;
758 for (int i = 0; i < nArLength; i++,index++)
760 m_arMethodInfos[index]= safe_cast<sr::MethodInfo^>(
761 map.TargetMethods[i]);
762 m_arInterfaceMethodInfos[index]= safe_cast<sr::MethodInfo^>(
763 map.InterfaceMethods[i]);
766 catch (System::InvalidCastException^ )
768 OUStringBuffer buf( 128 );
769 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
770 "[cli_uno bridge] preparing proxy for "
771 "cli interface: ") );
772 buf.append(mapCliString(m_type->ToString() ));
773 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" \nfailed!"));
774 throw BridgeRuntimeError( buf.makeStringAndClear() );
778 sr::MethodInfo^ CliProxy::getMethodInfo(int nUnoFunctionPos,
779 const rtl::OUString& usMethodName, MethodKind methodKind)
781 sr::MethodInfo^ ret = nullptr;
782 #if OSL_DEBUG_LEVEL >= 2
783 System::String* sMethodNameDbg;
784 sr::MethodInfo* arMethodInfosDbg[];
785 sr::MethodInfo* arInterfaceMethodInfosDbg[];
786 System::Int32 arInterfaceMethodCountDbg[];
787 System::Int32 arUnoPosToCliPosDbg[];
788 sMethodNameDbg = mapUnoString(usMethodName.pData);
789 arMethodInfosDbg = m_arMethodInfos;
790 arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos;
791 arInterfaceMethodCountDbg = m_arInterfaceMethodCount;
792 arUnoPosToCliPosDbg = m_arUnoPosToCliPos;
793 #endif
794 //deduct 3 for XInterface methods
795 nUnoFunctionPos -= 3;
796 System::Threading::Monitor::Enter(m_arUnoPosToCliPos);
799 int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos];
800 if (cliPos != -1)
801 return m_arMethodInfos[cliPos];
803 //create the method function name
804 System::String^ sMethodName = mapUnoString(usMethodName.pData);
805 switch (methodKind)
807 case MK_METHOD:
808 break;
809 case MK_SET:
810 sMethodName = System::String::Concat(
811 const_cast<System::String^>(Constants::sAttributeSet),
812 sMethodName);
813 break;
814 case MK_GET:
815 sMethodName = System::String::Concat(
816 const_cast<System::String^>(Constants::sAttributeGet),
817 sMethodName);
818 break;
819 default:
820 OSL_ASSERT(0);
822 //Find the cli interface method that corresponds to the Uno method
823 // System::String* sMethodName= mapUnoString(usMethodName.pData);
824 int indexCliMethod = -1;
825 //If the cli interfaces and their methods are in the same order
826 //as they were declared (inheritance chain and within the interface)
827 //then nUnoFunctionPos should lead to the correct method. However,
828 //the documentation does not say that this ordering is given.
829 if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name))
830 indexCliMethod = nUnoFunctionPos;
831 else
833 int cMethods = m_arInterfaceMethodInfos->Length;
834 for (int i = 0; i < cMethods; i++)
836 System::String^ cliMethod = m_arInterfaceMethodInfos[i]->Name;
837 if (cliMethod->Equals(sMethodName))
839 indexCliMethod = i;
840 break;
844 if (indexCliMethod == -1)
846 OUStringBuffer buf(256);
847 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
848 "[cli_uno bridge] CliProxy::getMethodInfo():"
849 "cli object does not implement interface method: "));
850 buf.append(usMethodName);
851 throw BridgeRuntimeError(buf.makeStringAndClear());
853 m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
854 ret = m_arMethodInfos[indexCliMethod];
856 __finally
858 System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
861 return ret;
864 CliProxy::~CliProxy()
866 #if OSL_DEBUG_LEVEL >= 2
867 sd::Trace::WriteLine(System::String::Format(
868 new System::String(
869 S"cli uno bridge: Destroying proxy for cli object, "
870 S"id:\n\t{0}\n\t{1}\n"),
871 m_oid, m_type));
872 #endif
873 CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get()));
874 m_bridge->release();
877 uno_Interface* CliProxy::create(Bridge const * bridge,
878 System::Object^ cliI,
879 typelib_TypeDescription const* pTD,
880 const rtl::OUString& ousOid)
882 uno_Interface* proxy= static_cast<uno_Interface*>(
883 new CliProxy(bridge, cliI, pTD, ousOid));
885 //register proxy with target environment (uno)
886 (*bridge->m_uno_env->registerProxyInterface)(
887 bridge->m_uno_env,
888 reinterpret_cast<void**>(&proxy),
889 cli_proxy_free,
890 ousOid.pData, (typelib_InterfaceTypeDescription*) pTD);
891 //register original interface
892 CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData),
893 mapUnoType((pTD)));
895 return proxy;
900 void SAL_CALL CliProxy::uno_DispatchMethod(
901 struct _uno_Interface *,
902 const struct _typelib_TypeDescription *,
903 void *,
904 void **,
905 uno_Any ** )
908 inline void CliProxy::acquire() const
910 if (1 == osl_atomic_increment( &m_ref ))
912 // rebirth of proxy zombie
913 void * that = const_cast< CliProxy * >( this );
914 // register at uno env
915 (*m_bridge->m_uno_env->registerProxyInterface)(
916 m_bridge->m_uno_env, &that,
917 cli_proxy_free, m_usOid.pData,
918 (typelib_InterfaceTypeDescription *)m_unoType.get() );
919 #if OSL_DEBUG_LEVEL >= 2
920 OSL_ASSERT( this == (void const * const)that );
921 #endif
924 //---------------------------------------------------------------------------
925 inline void CliProxy::release() const
927 if (0 == osl_atomic_decrement( &m_ref ))
929 // revoke from uno env on last release,
930 // The proxy can be resurrected if acquire is called before the uno
931 // environment calls cli_proxy_free. cli_proxy_free will
932 //delete the proxy. The environment does not acquire a registered
933 //proxy.
934 (*m_bridge->m_uno_env->revokeInterface)(
935 m_bridge->m_uno_env, const_cast< CliProxy * >( this ) );
943 extern "C"
944 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
945 SAL_THROW_EXTERN_C()
947 cli_uno::CliProxy * cliProxy = reinterpret_cast<
948 cli_uno::CliProxy * >( proxy );
950 delete cliProxy;
953 extern "C"
954 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
955 SAL_THROW_EXTERN_C()
957 CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
958 cliProxy->acquire();
960 //-----------------------------------------------------------------------------
961 extern "C"
962 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
963 SAL_THROW_EXTERN_C()
965 CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
966 cliProxy->release();
969 //------------------------------------------------------------------------------
970 extern "C"
972 void SAL_CALL cli_proxy_dispatch(
973 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
974 void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
975 SAL_THROW_EXTERN_C()
977 CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
980 Bridge const* bridge = proxy->m_bridge;
982 switch (member_td->eTypeClass)
984 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
987 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
988 member_td)->nPosition;
989 typelib_InterfaceTypeDescription * iface_td =
990 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
991 OSL_ENSURE(
992 member_pos < iface_td->nAllMembers,
993 "### member pos out of range!" );
994 sal_Int32 function_pos =
995 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
996 OSL_ENSURE(
997 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
998 "### illegal function index!" );
1000 if (uno_ret) // is getter method
1002 OUString const& usAttrName= *(rtl_uString**)&
1003 ((typelib_InterfaceMemberTypeDescription*) member_td)
1004 ->pMemberName;
1005 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
1006 usAttrName, CliProxy::MK_GET);
1007 bridge->call_cli(
1008 proxy->m_cliI,
1009 info,
1010 ((typelib_InterfaceAttributeTypeDescription *)member_td)
1011 ->pAttributeTypeRef,
1012 0, 0, // no params
1013 uno_ret, 0, uno_exc );
1015 else // is setter method
1017 OUString const& usAttrName= *(rtl_uString**) &
1018 ((typelib_InterfaceMemberTypeDescription*) member_td)
1019 ->pMemberName;
1020 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos + 1,
1021 usAttrName, CliProxy::MK_SET);
1022 typelib_MethodParameter param;
1023 param.pTypeRef =
1024 ((typelib_InterfaceAttributeTypeDescription *)member_td)
1025 ->pAttributeTypeRef;
1026 param.bIn = sal_True;
1027 param.bOut = sal_False;
1029 bridge->call_cli(
1030 proxy->m_cliI,
1031 // set follows get method
1032 info,
1033 0 /* indicates void return */, &param, 1,
1034 0, uno_args, uno_exc );
1036 break;
1038 case typelib_TypeClass_INTERFACE_METHOD:
1040 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
1041 member_td)->nPosition;
1042 typelib_InterfaceTypeDescription * iface_td =
1043 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
1044 OSL_ENSURE(
1045 member_pos < iface_td->nAllMembers,
1046 "### member pos out of range!" );
1047 sal_Int32 function_pos =
1048 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
1049 OSL_ENSURE(
1050 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
1051 "### illegal function index!" );
1053 switch (function_pos)
1055 case 0: // queryInterface()
1057 TypeDescr demanded_td(
1058 *reinterpret_cast<typelib_TypeDescriptionReference **>(
1059 uno_args[0]));
1060 if (typelib_TypeClass_INTERFACE
1061 != demanded_td.get()->eTypeClass)
1063 throw BridgeRuntimeError(
1064 OUSTR("queryInterface() call demands an INTERFACE type!"));
1067 uno_Interface * pInterface = 0;
1068 (*bridge->m_uno_env->getRegisteredInterface)(
1069 bridge->m_uno_env,
1070 (void **)&pInterface, proxy->m_usOid.pData,
1071 (typelib_InterfaceTypeDescription *)demanded_td.get() );
1073 if (0 == pInterface)
1075 System::Type^ mgdDemandedType =
1076 mapUnoType(demanded_td.get());
1077 if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
1079 #if OSL_DEBUG_LEVEL > 0
1080 OUString usOid(
1081 mapCliString(
1082 CliEnvHolder::g_cli_env->getObjectIdentifier(
1083 proxy->m_cliI )));
1084 OSL_ENSURE(usOid.equals( proxy->m_usOid ),
1085 "### different oids!");
1086 #endif
1087 uno_Interface* pUnoI = bridge->map_cli2uno(
1088 proxy->m_cliI, demanded_td.get() );
1089 uno_any_construct(
1090 (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 );
1091 (*pUnoI->release)( pUnoI );
1093 else // object does not support demanded interface
1095 uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
1097 // no excetpion occurred
1098 *uno_exc = 0;
1100 else
1102 uno_any_construct(
1103 reinterpret_cast< uno_Any * >( uno_ret ),
1104 &pInterface, demanded_td.get(), 0 );
1105 (*pInterface->release)( pInterface );
1106 *uno_exc = 0;
1108 break;
1110 case 1: // acquire this proxy
1111 cli_proxy_acquire(proxy);
1112 *uno_exc = 0;
1113 break;
1114 case 2: // release this proxy
1115 cli_proxy_release(proxy);
1116 *uno_exc = 0;
1117 break;
1118 default: // arbitrary method call
1120 typelib_InterfaceMethodTypeDescription * method_td =
1121 (typelib_InterfaceMethodTypeDescription *)member_td;
1122 OUString const& usMethodName= *(rtl_uString**) &
1123 ((typelib_InterfaceMemberTypeDescription*) member_td)
1124 ->pMemberName;
1126 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
1127 usMethodName, CliProxy::MK_METHOD);
1128 bridge->call_cli(
1129 proxy->m_cliI,
1130 info,
1131 method_td->pReturnTypeRef, method_td->pParams,
1132 method_td->nParams,
1133 uno_ret, uno_args, uno_exc);
1134 return;
1137 break;
1139 default:
1141 throw BridgeRuntimeError(
1142 OUSTR("illegal member type description!") );
1146 catch (BridgeRuntimeError & err)
1148 // binary identical struct
1149 ::com::sun::star::uno::RuntimeException exc(
1150 OUSTR("[cli_uno bridge error] ") + err.m_message,
1151 ::com::sun::star::uno::Reference<
1152 ::com::sun::star::uno::XInterface >() );
1153 ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc);
1154 uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0);
1155 #if OSL_DEBUG_LEVEL >= 1
1156 OString cstr_msg(OUStringToOString(exc.Message,
1157 RTL_TEXTENCODING_ASCII_US ) );
1158 OSL_FAIL(cstr_msg.getStr());
1159 #endif
1167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */