Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / cli_ure / source / uno_bridge / cli_proxy.cxx
blob22c47817748f88ad42580a6ade160a94dec24d1c
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 <sal/log.hxx>
23 #include "com/sun/star/uno/RuntimeException.hpp"
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 extern "C"
45 void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy )
46 SAL_THROW_EXTERN_C();
48 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
49 SAL_THROW_EXTERN_C();
51 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
52 SAL_THROW_EXTERN_C();
54 void SAL_CALL cli_proxy_dispatch(
55 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
56 void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
57 SAL_THROW_EXTERN_C();
62 namespace cli_uno
65 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
66 typelib_InterfaceTypeDescription* td):
68 m_unoI(unoI),
69 m_typeDesc(td),
70 m_bridge(bridge)
72 m_bridge->acquire();
73 m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td));
74 m_unoI->acquire(m_unoI);
75 typelib_typedescription_acquire(&m_typeDesc->aBase);
76 if ( ! m_typeDesc->aBase.bComplete)
78 typelib_TypeDescription* _pt = &m_typeDesc->aBase;
79 sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
80 if( ! bComplete)
82 throw BridgeRuntimeError("cannot make type complete: " + OUString::unacquired(& m_typeDesc->aBase.pTypeName));
87 UnoInterfaceInfo::~UnoInterfaceInfo() ///< IDisposable UnoInterfaceInfo::Dispose()
89 this->!UnoInterfaceInfo(); // call finalizer
92 UnoInterfaceInfo::!UnoInterfaceInfo() ///< UnoInterfaceInfo::Finalize()
94 //accessing unmanaged objects is ok.
95 m_bridge->m_uno_env->revokeInterface(
96 m_bridge->m_uno_env, m_unoI );
97 m_bridge->release();
99 m_unoI->release(m_unoI);
100 typelib_typedescription_release(
101 reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
104 UnoInterfaceProxy::UnoInterfaceProxy(
105 Bridge * bridge,
106 uno_Interface * pUnoI,
107 typelib_InterfaceTypeDescription* pTD,
108 const OUString& oid )
109 :RealProxy(MarshalByRefObject::typeid),
110 m_bridge(bridge),
111 m_oid(mapUnoString(oid.pData)),
112 m_sTypeName(m_system_Object_String)
114 m_bridge->acquire();
115 // create the list that holds all UnoInterfaceInfos
116 m_listIfaces = gcnew ArrayList(10);
117 m_numUnoIfaces = 0;
118 m_listAdditionalProxies = gcnew ArrayList();
119 m_nlistAdditionalProxies = 0;
120 //put the information of the first UNO interface into the arraylist
121 #if OSL_DEBUG_LEVEL >= 2
122 _numInterfaces = 0;
123 _sInterfaces = NULL;
124 #endif
125 addUnoInterface(pUnoI, pTD);
129 UnoInterfaceProxy::~UnoInterfaceProxy() ///< IDisposable UnoInterfaceProxy::Dispose()
131 this->!UnoInterfaceProxy(); // call finalizer
134 UnoInterfaceProxy::!UnoInterfaceProxy() ///< UnoInterfaceProxy::Finalize()
136 #if OSL_DEBUG_LEVEL >= 2
137 sd::Trace::WriteLine(System::String::Format(
138 gcnew System::String("cli uno bridge: Destroying proxy "
139 "for UNO object, OID: \n\t{0} \n\twith uno interfaces: "),
140 m_oid));
142 sd::Trace::WriteLine( mapUnoString(_sInterfaces));
143 rtl_uString_release(_sInterfaces);
144 #endif
145 //m_bridge is unmanaged, therefore we can access it in this finalizer
146 CliEnvHolder::g_cli_env->revokeInterface(m_oid);
147 m_bridge->release();
150 System::Object^ UnoInterfaceProxy::create(
151 Bridge * bridge,
152 uno_Interface * pUnoI,
153 typelib_InterfaceTypeDescription* pTD,
154 const OUString& oid)
156 UnoInterfaceProxy^ proxyHandler=
157 gcnew UnoInterfaceProxy(bridge, pUnoI, pTD, oid);
158 System::Object^ proxy= proxyHandler->GetTransparentProxy();
159 CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData));
160 return proxy;
164 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
165 typelib_InterfaceTypeDescription* pTd)
167 sc::IEnumerator^ enumInfos = m_listIfaces->GetEnumerator();
168 System::Threading::Monitor::Enter(this);
171 while (enumInfos->MoveNext())
173 UnoInterfaceInfo^ info = static_cast<UnoInterfaceInfo^>(
174 enumInfos->Current);
175 if (typelib_typedescription_equals(
176 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc),
177 reinterpret_cast<typelib_TypeDescription*>(pTd)))
179 return;
182 OUString oid(mapCliString(m_oid));
183 (*m_bridge->m_uno_env->registerInterface)(
184 m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
185 oid.pData, pTd);
186 //This proxy does not contain the uno_Interface. Add it.
187 m_listIfaces->Add(gcnew UnoInterfaceInfo(m_bridge, pUnoI, pTd));
188 m_numUnoIfaces = m_listIfaces->Count;
189 #if OSL_DEBUG_LEVEL >= 2
190 System::String^ sInterfaceName = static_cast<UnoInterfaceInfo^>(
191 m_listIfaces[m_numUnoIfaces - 1])->m_type->FullName;
192 sd::Trace::WriteLine(System::String::Format(
193 gcnew System::String("cli uno bridge: Creating proxy for uno object, "
194 "id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName));
195 // add to the string that contains all interface names
196 _numInterfaces++;
197 OUString _sNewInterface = "\t" + OUString::number(_numInterfaces) + ". " + mapCliString(sInterfaceName) + "\n";
198 pin_ptr<rtl_uString *> pp_sInterfaces = &_sInterfaces;
199 rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces,
200 _sNewInterface.pData);
201 #endif
203 __finally {
204 System::Threading::Monitor::Exit(this);
209 // IRemotingTypeInfo
210 bool UnoInterfaceProxy::CanCastTo(System::Type^ fromType,
211 System::Object^)
213 if (fromType == System::Object::typeid) // trivial case
214 return true;
216 System::Threading::Monitor::Enter(this);
219 if (nullptr != findInfo( fromType )) // proxy supports demanded interface
220 return true;
222 //query a uno interface for the required type
224 // we use the first interface in the list (m_listIfaces) to make
225 // the queryInterface call
226 UnoInterfaceInfo^ info =
227 static_cast<UnoInterfaceInfo^>(m_listIfaces[0]);
228 css::uno::TypeDescription membertd(
229 reinterpret_cast<typelib_InterfaceTypeDescription*>(
230 info->m_typeDesc)->ppAllMembers[0]);
231 array<System::Object^>^ args = gcnew array<System::Object^>(1);
233 args[0] = fromType;
234 uno::Any ^ pAny;
235 System::Object^ pException = nullptr;
237 pAny= static_cast<uno::Any ^>(
238 m_bridge->call_uno(
239 info->m_unoI,
240 membertd.get(),
241 ((typelib_InterfaceMethodTypeDescription*)
242 membertd.get())->pReturnTypeRef,
244 ((typelib_InterfaceMethodTypeDescription*)
245 membertd.get())->pParams,
246 args, nullptr, &pException) );
248 // handle regular exception from target
249 OSL_ENSURE(
250 nullptr == pException,
251 OUStringToOString(
252 mapCliString( pException->ToString()),
253 RTL_TEXTENCODING_UTF8 ).getStr() );
255 if (pAny->Type != void::typeid) // has value?
257 if (nullptr != findInfo( fromType ))
259 // proxy now supports demanded interface
260 return true;
263 // via aggregation: it is possible that queryInterface() returns
264 // and interface with a different oid.
265 // That way, this type is supported for the CLI
266 // interpreter (CanCastTo() returns true)
267 ::System::Object ^ obj = pAny->Value;
268 OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) );
269 if (srr::RemotingServices::IsTransparentProxy( obj ))
271 UnoInterfaceProxy ^ proxy =
272 static_cast< UnoInterfaceProxy ^ >(
273 srr::RemotingServices::GetRealProxy( obj ) );
274 OSL_ASSERT( nullptr != proxy->findInfo( fromType ) );
275 m_listAdditionalProxies->Add( proxy );
276 m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
277 OSL_ASSERT( nullptr != findInfo( fromType ) );
278 return true;
282 catch (BridgeRuntimeError& e)
284 (void) e; // avoid warning
285 OSL_FAIL(
286 OUStringToOString(
287 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
289 catch (System::Exception^ e)
291 System::String^ msg= gcnew System::String(
292 "An unexpected CLI exception occurred in "
293 "UnoInterfaceProxy::CanCastTo(). Original"
294 "message: \n");
295 msg= System::String::Concat(msg, e->Message);
296 OSL_FAIL(
297 OUStringToOString(
298 mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() );
300 catch (...)
302 OSL_FAIL(
303 "An unexpected native C++ exception occurred in "
304 "UnoInterfaceProxy::CanCastTo()" );
306 __finally
308 System::Threading::Monitor::Exit(this);
310 return false;
313 srrm::IMessage^ UnoInterfaceProxy::invokeObject(
314 sc::IDictionary^ props,
315 srrm::LogicalCallContext^ context,
316 srrm::IMethodCallMessage^ mcm)
318 System::Object^ retMethod = nullptr;
319 System::String^ sMethod = static_cast<System::String^>
320 (props[m_methodNameString]);
321 array<System::Object^>^ args = static_cast<array<System::Object^>^>(
322 props[m_ArgsString]);
323 if (m_Equals_String->Equals(sMethod))
325 // Object.Equals
326 OSL_ASSERT(args->Length == 1);
327 srrp::RealProxy^ rProxy = srr::RemotingServices::GetRealProxy(args[0]);
328 bool bDone = false;
329 if (rProxy)
331 UnoInterfaceProxy^ unoProxy =
332 dynamic_cast<UnoInterfaceProxy^>(rProxy);
333 if (unoProxy)
335 bool b = m_oid->Equals(unoProxy->getOid());
336 retMethod = b;
337 bDone = true;
340 if (bDone == false)
342 //no proxy or not our proxy, therefore Equals must be false
343 retMethod = false;
346 else if (m_GetHashCode_String->Equals(sMethod))
348 // Object.GetHashCode
349 int nHash = m_oid->GetHashCode();
350 retMethod = nHash;
352 else if (m_GetType_String->Equals(sMethod))
354 // Object.GetType
355 retMethod = System::Object::typeid;
357 else if (m_ToString_String->Equals(sMethod))
359 // Object.ToString
360 st::StringBuilder^ sb = gcnew st::StringBuilder(256);
361 // sb->AppendFormat("Uno object proxy. Implemented interface: {0}"
362 // ". OID: {1}", m_type->ToString(), m_oid);
363 sb->AppendFormat("Uno object proxy. OID: {0}", m_oid);
364 retMethod = sb->ToString();
366 else
368 //Either Object has new functions or a protected method was called
369 //which should not be possible
370 OSL_ASSERT(0);
372 srrm::IMessage^ retVal= gcnew srrm::ReturnMessage(
373 retMethod, gcnew array<System::Object^>(0), 0, context, mcm);
374 return retVal;
377 UnoInterfaceInfo ^ UnoInterfaceProxy::findInfo( ::System::Type ^ type )
379 for (int i = 0; i < m_numUnoIfaces; i++)
381 UnoInterfaceInfo^ tmpInfo = static_cast<UnoInterfaceInfo^>(
382 m_listIfaces[i]);
383 if (type->IsAssignableFrom(tmpInfo->m_type))
384 return tmpInfo;
386 for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
388 UnoInterfaceProxy ^ proxy =
389 static_cast< UnoInterfaceProxy ^ >(
390 m_listAdditionalProxies[ i ] );
391 UnoInterfaceInfo ^ info = proxy->findInfo( type );
392 if (nullptr != info)
393 return info;
395 return nullptr;
398 srrm::IMessage^ UnoInterfaceProxy::Invoke(srrm::IMessage^ callmsg)
402 sc::IDictionary^ props= callmsg->Properties;
403 srrm::LogicalCallContext^ context=
404 static_cast<srrm::LogicalCallContext^>(
405 props[m_CallContextString]);
406 srrm::IMethodCallMessage^ mcm=
407 static_cast<srrm::IMethodCallMessage^>(callmsg);
409 //Find out which UNO interface is being called
410 System::String^ sTypeName = static_cast<System::String^>(
411 props[m_typeNameString]);
412 sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(','));
414 // Special Handling for System.Object methods
415 if(sTypeName->IndexOf(m_system_Object_String) != -1)
417 return invokeObject(props, context, mcm);
420 System::Type^ typeBeingCalled = loadCliType(sTypeName);
421 UnoInterfaceInfo^ info = findInfo( typeBeingCalled );
422 OSL_ASSERT( nullptr != info );
424 // ToDo do without string conversion, an OUString is not needed here
425 // get the type description of the call
426 OUString usMethodName(mapCliString(static_cast<System::String^>(
427 props[m_methodNameString])));
428 typelib_TypeDescriptionReference ** ppAllMembers =
429 info->m_typeDesc->ppAllMembers;
430 sal_Int32 numberMembers = info->m_typeDesc->nAllMembers;
431 for ( sal_Int32 nPos = numberMembers; nPos--; )
433 typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
435 // check usMethodName against fully qualified usTypeName
436 // of member_type; usTypeName is of the form
437 // <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>)
438 OUString const & usTypeName =
439 OUString::unacquired( & member_type->pTypeName );
441 #if OSL_DEBUG_LEVEL >= 2
442 System::String^ pTypeName;
443 pTypeName = mapUnoString(usTypeName.pData);
444 #endif
445 sal_Int32 offset = usTypeName.indexOf( ':' ) + 2;
446 OSL_ASSERT(
447 offset >= 2 && offset < usTypeName.getLength()
448 && usTypeName[offset - 1] == ':' );
449 sal_Int32 remainder = usTypeName.getLength() - offset;
451 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
453 if ((usMethodName.getLength() == remainder
454 || (usMethodName.getLength() < remainder
455 && usTypeName[offset + usMethodName.getLength()] == ':'))
456 && usTypeName.match(usMethodName, offset))
458 TypeDescr member_td( member_type );
459 typelib_InterfaceMethodTypeDescription * method_td =
460 (typelib_InterfaceMethodTypeDescription *)
461 member_td.get();
463 array<System::Object^>^ args = static_cast<array<System::Object^>^>(
464 props[m_ArgsString]);
465 array<System::Type^>^ argTypes = static_cast<array<System::Type^>^>(
466 props[m_methodSignatureString]);
467 System::Object^ pExc = nullptr;
468 System::Object ^ cli_ret = m_bridge->call_uno(
469 info->m_unoI, member_td.get(),
470 method_td->pReturnTypeRef, method_td->nParams,
471 method_td->pParams, args, argTypes, &pExc);
472 return constructReturnMessage(cli_ret, args, method_td,
473 callmsg, pExc);
476 else
478 OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE ==
479 member_type->eTypeClass );
480 if (usMethodName.getLength() > 4
481 && (usMethodName.getLength() - 4 == remainder
482 || (usMethodName.getLength() - 4 < remainder
483 && usTypeName[
484 offset + (usMethodName.getLength() - 4)] == ':'))
485 && usMethodName[1] == 'e' && usMethodName[2] == 't'
486 && rtl_ustr_compare_WithLength(
487 usTypeName.getStr() + offset,
488 usMethodName.getLength() - 4,
489 usMethodName.getStr() + 4,
490 usMethodName.getLength() - 4) == 0)
492 if ('g' == usMethodName[0])
494 TypeDescr member_td( member_type );
495 typelib_InterfaceAttributeTypeDescription * attribute_td =
496 (typelib_InterfaceAttributeTypeDescription*)
497 member_td.get();
499 System::Object^ pExc = nullptr;
500 System::Object^ cli_ret= m_bridge->call_uno(
501 info->m_unoI, member_td.get(),
502 attribute_td->pAttributeTypeRef,
503 0, 0,
504 nullptr, nullptr, &pExc);
505 return constructReturnMessage(cli_ret, nullptr, NULL,
506 callmsg, pExc);
508 else if ('s' == usMethodName[0])
510 TypeDescr member_td( member_type );
511 typelib_InterfaceAttributeTypeDescription * attribute_td =
512 (typelib_InterfaceAttributeTypeDescription *)
513 member_td.get();
514 if (! attribute_td->bReadOnly)
516 typelib_MethodParameter param;
517 param.pTypeRef = attribute_td->pAttributeTypeRef;
518 param.bIn = sal_True;
519 param.bOut = sal_False;
521 array<System::Object^>^ args =
522 static_cast<array<System::Object^>^>(
523 props[m_ArgsString]);
524 System::Object^ pExc = nullptr;
525 m_bridge->call_uno(
526 info->m_unoI, member_td.get(),
527 cppu::UnoType<void>::get().getTypeLibType(),
528 1, &param, args, nullptr, &pExc);
529 return constructReturnMessage(nullptr, nullptr, NULL,
530 callmsg, pExc);
532 else
534 return constructReturnMessage(nullptr, nullptr, NULL,
535 callmsg, nullptr);
538 break;
542 // ToDo check if the message of the exception is not crippled
543 // the thing that should not be... no method info found!
544 throw BridgeRuntimeError("[cli_uno bridge]calling undeclared function on interface " +
545 OUString::unacquired(& ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName) +
546 ": " + usMethodName);
548 catch (BridgeRuntimeError & err)
550 srrm::IMethodCallMessage^ mcm =
551 static_cast<srrm::IMethodCallMessage^>(callmsg);
552 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
553 mapUnoString(err.m_message.pData), nullptr), mcm);
555 catch (System::Exception^ e)
557 st::StringBuilder ^ sb = gcnew st::StringBuilder(512);
558 sb->Append(gcnew System::String(
559 "An unexpected CLI exception occurred in "
560 "UnoInterfaceProxy::Invoke. Original"
561 "message: \n"));
562 sb->Append(e->Message);
563 sb->Append((__wchar_t) '\n');
564 sb->Append(e->StackTrace);
565 srrm::IMethodCallMessage^ mcm =
566 static_cast<srrm::IMethodCallMessage^>(callmsg);
567 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
568 sb->ToString(), nullptr), mcm);
570 catch (...)
572 System::String^ msg = gcnew System::String(
573 "An unexpected native C++ exception occurred in "
574 "UnoInterfaceProxy::Invoke.");
575 srrm::IMethodCallMessage^ mcm =
576 static_cast<srrm::IMethodCallMessage^>(callmsg);
577 return gcnew srrm::ReturnMessage(gcnew ucss::uno::RuntimeException(
578 msg, nullptr), mcm);
580 return nullptr;
582 /** If the argument args is NULL then this function is called for an attribute
583 method (either setXXX or getXXX).
584 For attributes the argument mtd is also NULL.
586 srrm::IMessage^ UnoInterfaceProxy::constructReturnMessage(
587 System::Object^ cliReturn,
588 array<System::Object^>^ args,
589 typelib_InterfaceMethodTypeDescription* mtd,
590 srrm::IMessage^ msg, System::Object^ exc)
592 srrm::IMessage ^ retVal= nullptr;
593 srrm::IMethodCallMessage^ mcm = static_cast<srrm::IMethodCallMessage^>(msg);
594 if (exc)
596 retVal = gcnew srrm::ReturnMessage(
597 dynamic_cast<System::Exception^>(exc), mcm);
599 else
601 sc::IDictionary^ props= msg->Properties;
602 srrm::LogicalCallContext^ context=
603 static_cast<srrm::LogicalCallContext^>(
604 props[m_CallContextString]);
605 if (args != nullptr)
607 // Method
608 //build the array of out parameters, allocate max length
609 array<System::Object^>^ arOut= gcnew array<System::Object^>(mtd->nParams);
610 int nOut = 0;
611 for (int i= 0; i < mtd->nParams; i++)
613 if (mtd->pParams[i].bOut)
615 arOut[i]= args[i];
616 nOut++;
619 retVal= gcnew srrm::ReturnMessage(cliReturn, arOut, nOut,
620 context, mcm);
622 else
624 // Attribute (getXXX)
625 retVal= gcnew srrm::ReturnMessage(cliReturn, nullptr, 0,
626 context, mcm);
629 return retVal;
633 CliProxy::CliProxy(Bridge const* bridge, System::Object^ cliI,
634 typelib_TypeDescription const* td,
635 const OUString& usOid):
636 m_ref(1),
637 m_bridge(bridge),
638 m_cliI(cliI),
639 m_unoType(const_cast<typelib_TypeDescription*>(td)),
640 m_usOid(usOid),
641 m_oid(mapUnoString(usOid.pData)),
642 m_nInheritedInterfaces(0)
644 m_bridge->acquire();
645 uno_Interface::acquire = cli_proxy_acquire;
646 uno_Interface::release = cli_proxy_release;
647 uno_Interface::pDispatcher = cli_proxy_dispatch;
649 m_unoType.makeComplete();
650 m_type= mapUnoType(m_unoType.get());
652 makeMethodInfos();
653 #if OSL_DEBUG_LEVEL >= 2
654 sd::Trace::WriteLine(System::String::Format(
655 gcnew System::String("cli uno bridge: Creating proxy for cli object, "
656 "id:\n\t{0}\n\t{1}"), m_oid, m_type));
657 #endif
661 void CliProxy::makeMethodInfos()
663 #if OSL_DEBUG_LEVEL >= 2
664 System::Object^ cliI;
665 System::Type^ type;
666 cliI = m_cliI;
667 type = m_type;
668 #endif
670 if (m_type->IsInterface == false)
671 return;
672 array<sr::MethodInfo^>^ arThisMethods = m_type->GetMethods();
673 //get the inherited interfaces
674 array<System::Type^>^ arInheritedIfaces = m_type->GetInterfaces();
675 m_nInheritedInterfaces = arInheritedIfaces->Length;
676 //array containing the number of methods for the interface and its
677 //inherited interfaces
678 m_arInterfaceMethodCount = gcnew array<int^>(m_nInheritedInterfaces + 1);
679 //determine the number of all interface methods, including the inherited
680 //interfaces
681 int numMethods = arThisMethods->Length;
682 for (int i= 0; i < m_nInheritedInterfaces; i++)
684 numMethods += arInheritedIfaces[i]->GetMethods()->Length;
686 //array containing MethodInfos of the cli object
687 m_arMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
688 //array containing MethodInfos of the interface
689 m_arInterfaceMethodInfos = gcnew array<sr::MethodInfo^>(numMethods);
690 //array containing the mapping of Uno interface pos to pos in
691 //m_arMethodInfos
692 m_arUnoPosToCliPos = gcnew array<System::Int32>(numMethods);
693 // initialize with -1
694 for (int i = 0; i < numMethods; i++)
695 m_arUnoPosToCliPos[i] = -1;
697 //fill m_arMethodInfos with the mappings
698 // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
699 // to documentation
700 // but it is Type*[] instead. Bug in the framework?
701 System::Type^ objType = m_cliI->GetType();
704 int index = 0;
705 // now get the methods from the inherited interface
706 //arInheritedIfaces[0] is the direct base interface
707 //arInheritedIfaces[n] is the furthest inherited interface
708 //Start with the base interface
709 int nArLength = arInheritedIfaces->Length;
710 for (;nArLength > 0; nArLength--)
712 sr::InterfaceMapping mapInherited = objType->GetInterfaceMap(
713 arInheritedIfaces[nArLength - 1]);
714 int numMethods = mapInherited.TargetMethods->Length;
715 m_arInterfaceMethodCount[nArLength - 1] = numMethods;
716 for (int i = 0; i < numMethods; i++, index++)
718 m_arMethodInfos[index] = safe_cast<sr::MethodInfo^>(
719 mapInherited.TargetMethods[i]);
721 m_arInterfaceMethodInfos[index] = safe_cast<sr::MethodInfo^>(
722 mapInherited.InterfaceMethods[i]);
725 //At last come the methods of the furthest derived interface
726 sr::InterfaceMapping map = objType->GetInterfaceMap(m_type);
727 nArLength = map.TargetMethods->Length;
728 m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength;
729 for (int i = 0; i < nArLength; i++,index++)
731 m_arMethodInfos[index]= safe_cast<sr::MethodInfo^>(
732 map.TargetMethods[i]);
733 m_arInterfaceMethodInfos[index]= safe_cast<sr::MethodInfo^>(
734 map.InterfaceMethods[i]);
737 catch (System::InvalidCastException^ )
739 throw BridgeRuntimeError("[cli_uno bridge] preparing proxy for cli interface: " + mapCliString(m_type->ToString()) + " \nfailed!");
743 sr::MethodInfo^ CliProxy::getMethodInfo(int nUnoFunctionPos,
744 const OUString& usMethodName, MethodKind methodKind)
746 sr::MethodInfo^ ret = nullptr;
747 //deduct 3 for XInterface methods
748 nUnoFunctionPos -= 3;
749 System::Threading::Monitor::Enter(m_arUnoPosToCliPos);
752 int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos];
753 if (cliPos != -1)
754 return m_arMethodInfos[cliPos];
756 //create the method function name
757 System::String^ sMethodName = mapUnoString(usMethodName.pData);
758 switch (methodKind)
760 case MK_METHOD:
761 break;
762 case MK_SET:
763 sMethodName = System::String::Concat(
764 const_cast<System::String^>(Constants::sAttributeSet),
765 sMethodName);
766 break;
767 case MK_GET:
768 sMethodName = System::String::Concat(
769 const_cast<System::String^>(Constants::sAttributeGet),
770 sMethodName);
771 break;
772 default:
773 OSL_ASSERT(0);
775 //Find the cli interface method that corresponds to the Uno method
776 // System::String* sMethodName= mapUnoString(usMethodName.pData);
777 int indexCliMethod = -1;
778 //If the cli interfaces and their methods are in the same order
779 //as they were declared (inheritance chain and within the interface)
780 //then nUnoFunctionPos should lead to the correct method. However,
781 //the documentation does not say that this ordering is given.
782 if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name))
783 indexCliMethod = nUnoFunctionPos;
784 else
786 int cMethods = m_arInterfaceMethodInfos->Length;
787 for (int i = 0; i < cMethods; i++)
789 System::String^ cliMethod = m_arInterfaceMethodInfos[i]->Name;
790 if (cliMethod->Equals(sMethodName))
792 indexCliMethod = i;
793 break;
797 if (indexCliMethod == -1)
799 throw BridgeRuntimeError("[cli_uno bridge] CliProxy::getMethodInfo():cli object does not implement interface method: " + usMethodName);
801 m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
802 ret = m_arMethodInfos[indexCliMethod];
804 __finally
806 System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
809 return ret;
812 CliProxy::~CliProxy()
814 #if OSL_DEBUG_LEVEL >= 2
815 sd::Trace::WriteLine(System::String::Format(
816 gcnew System::String(
817 "cli uno bridge: Destroying proxy for cli object, "
818 "id:\n\t{0}\n\t{1}\n"),
819 m_oid, m_type));
820 #endif
821 CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get()));
822 m_bridge->release();
825 uno_Interface* CliProxy::create(Bridge const * bridge,
826 System::Object^ cliI,
827 typelib_TypeDescription const* pTD,
828 const OUString& ousOid)
830 uno_Interface* proxy= static_cast<uno_Interface*>(
831 new CliProxy(bridge, cliI, pTD, ousOid));
833 //register proxy with target environment (uno)
834 (*bridge->m_uno_env->registerProxyInterface)(
835 bridge->m_uno_env,
836 reinterpret_cast<void**>(&proxy),
837 cli_proxy_free,
838 ousOid.pData, (typelib_InterfaceTypeDescription*) pTD);
839 //register original interface
840 CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData),
841 mapUnoType((pTD)));
843 return proxy;
847 void SAL_CALL CliProxy::uno_DispatchMethod(
848 struct _uno_Interface *,
849 const struct _typelib_TypeDescription *,
850 void *,
851 void **,
852 uno_Any ** )
855 inline void CliProxy::acquire() const
857 if (1 == osl_atomic_increment( &m_ref ))
859 // rebirth of proxy zombie
860 void * that = const_cast< CliProxy * >( this );
861 // register at uno env
862 (*m_bridge->m_uno_env->registerProxyInterface)(
863 m_bridge->m_uno_env, &that,
864 cli_proxy_free, m_usOid.pData,
865 (typelib_InterfaceTypeDescription *)m_unoType.get() );
866 #if OSL_DEBUG_LEVEL >= 2
867 OSL_ASSERT( this == (void const * const)that );
868 #endif
872 inline void CliProxy::release() const
874 if (0 == osl_atomic_decrement( &m_ref ))
876 // revoke from uno env on last release,
877 // The proxy can be resurrected if acquire is called before the uno
878 // environment calls cli_proxy_free. cli_proxy_free will
879 //delete the proxy. The environment does not acquire a registered
880 //proxy.
881 (*m_bridge->m_uno_env->revokeInterface)(
882 m_bridge->m_uno_env, const_cast< CliProxy * >( this ) );
888 extern "C"
889 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
890 SAL_THROW_EXTERN_C()
892 cli_uno::CliProxy * cliProxy = reinterpret_cast<
893 cli_uno::CliProxy * >( proxy );
895 delete cliProxy;
898 extern "C"
899 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
900 SAL_THROW_EXTERN_C()
902 CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
903 cliProxy->acquire();
906 extern "C"
907 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
908 SAL_THROW_EXTERN_C()
910 CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
911 cliProxy->release();
915 extern "C"
917 void SAL_CALL cli_proxy_dispatch(
918 uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
919 void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
920 SAL_THROW_EXTERN_C()
922 CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
925 Bridge const* bridge = proxy->m_bridge;
927 switch (member_td->eTypeClass)
929 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
932 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
933 member_td)->nPosition;
934 typelib_InterfaceTypeDescription * iface_td =
935 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
936 OSL_ENSURE(
937 member_pos < iface_td->nAllMembers,
938 "### member pos out of range!" );
939 sal_Int32 function_pos =
940 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
941 OSL_ENSURE(
942 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
943 "### illegal function index!" );
945 if (uno_ret) // is getter method
947 OUString const& usAttrName= *(rtl_uString**)&
948 ((typelib_InterfaceMemberTypeDescription*) member_td)
949 ->pMemberName;
950 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
951 usAttrName, CliProxy::MK_GET);
952 bridge->call_cli(
953 proxy->m_cliI,
954 info,
955 ((typelib_InterfaceAttributeTypeDescription *)member_td)
956 ->pAttributeTypeRef,
957 0, 0, // no params
958 uno_ret, 0, uno_exc );
960 else // is setter method
962 OUString const& usAttrName= *(rtl_uString**) &
963 ((typelib_InterfaceMemberTypeDescription*) member_td)
964 ->pMemberName;
965 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos + 1,
966 usAttrName, CliProxy::MK_SET);
967 typelib_MethodParameter param;
968 param.pTypeRef =
969 ((typelib_InterfaceAttributeTypeDescription *)member_td)
970 ->pAttributeTypeRef;
971 param.bIn = sal_True;
972 param.bOut = sal_False;
974 bridge->call_cli(
975 proxy->m_cliI,
976 // set follows get method
977 info,
978 0 /* indicates void return */, &param, 1,
979 0, uno_args, uno_exc );
981 break;
983 case typelib_TypeClass_INTERFACE_METHOD:
985 sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
986 member_td)->nPosition;
987 typelib_InterfaceTypeDescription * iface_td =
988 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
989 OSL_ENSURE(
990 member_pos < iface_td->nAllMembers,
991 "### member pos out of range!" );
992 sal_Int32 function_pos =
993 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
994 OSL_ENSURE(
995 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
996 "### illegal function index!" );
998 switch (function_pos)
1000 case 0: // queryInterface()
1002 TypeDescr demanded_td(
1003 *reinterpret_cast<typelib_TypeDescriptionReference **>(
1004 uno_args[0]));
1005 if (typelib_TypeClass_INTERFACE
1006 != demanded_td.get()->eTypeClass)
1008 throw BridgeRuntimeError(
1009 "queryInterface() call demands an INTERFACE type!");
1012 uno_Interface * pInterface = 0;
1013 (*bridge->m_uno_env->getRegisteredInterface)(
1014 bridge->m_uno_env,
1015 (void **)&pInterface, proxy->m_usOid.pData,
1016 (typelib_InterfaceTypeDescription *)demanded_td.get() );
1018 if (0 == pInterface)
1020 System::Type^ mgdDemandedType =
1021 mapUnoType(demanded_td.get());
1022 if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
1024 #if OSL_DEBUG_LEVEL > 0
1025 OUString usOid(
1026 mapCliString(
1027 CliEnvHolder::g_cli_env->getObjectIdentifier(
1028 proxy->m_cliI )));
1029 OSL_ENSURE(usOid.equals( proxy->m_usOid ),
1030 "### different oids!");
1031 #endif
1032 uno_Interface* pUnoI = bridge->map_cli2uno(
1033 proxy->m_cliI, demanded_td.get() );
1034 uno_any_construct(
1035 (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 );
1036 (*pUnoI->release)( pUnoI );
1038 else // object does not support demanded interface
1040 uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
1042 // no exception occurred
1043 *uno_exc = 0;
1045 else
1047 uno_any_construct(
1048 reinterpret_cast< uno_Any * >( uno_ret ),
1049 &pInterface, demanded_td.get(), 0 );
1050 (*pInterface->release)( pInterface );
1051 *uno_exc = 0;
1053 break;
1055 case 1: // acquire this proxy
1056 cli_proxy_acquire(proxy);
1057 *uno_exc = 0;
1058 break;
1059 case 2: // release this proxy
1060 cli_proxy_release(proxy);
1061 *uno_exc = 0;
1062 break;
1063 default: // arbitrary method call
1065 typelib_InterfaceMethodTypeDescription * method_td =
1066 (typelib_InterfaceMethodTypeDescription *)member_td;
1067 OUString const& usMethodName= *(rtl_uString**) &
1068 ((typelib_InterfaceMemberTypeDescription*) member_td)
1069 ->pMemberName;
1071 sr::MethodInfo^ info = proxy->getMethodInfo(function_pos,
1072 usMethodName, CliProxy::MK_METHOD);
1073 bridge->call_cli(
1074 proxy->m_cliI,
1075 info,
1076 method_td->pReturnTypeRef, method_td->pParams,
1077 method_td->nParams,
1078 uno_ret, uno_args, uno_exc);
1079 return;
1082 break;
1084 default:
1086 throw BridgeRuntimeError(
1087 "illegal member type description!" );
1091 catch (BridgeRuntimeError & err)
1093 // binary identical struct
1094 css::uno::RuntimeException exc(
1095 "[cli_uno bridge error] " + err.m_message,
1096 css::uno::Reference<
1097 css::uno::XInterface >() );
1098 css::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
1099 uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0);
1100 SAL_WARN( "cli", exc);
1105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */