1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
26 #include "cli_bridge.h"
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
;
45 void SAL_CALL
cli_proxy_free( uno_ExtEnvironment
* env
, void * proxy
)
48 void SAL_CALL
cli_proxy_acquire( uno_Interface
* pUnoI
)
51 void SAL_CALL
cli_proxy_release( uno_Interface
* pUnoI
)
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
)
65 UnoInterfaceInfo::UnoInterfaceInfo(Bridge
const * bridge
, uno_Interface
* unoI
,
66 typelib_InterfaceTypeDescription
* td
):
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
);
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
);
99 m_unoI
->release(m_unoI
);
100 typelib_typedescription_release(
101 reinterpret_cast<typelib_TypeDescription
*>(m_typeDesc
));
104 UnoInterfaceProxy::UnoInterfaceProxy(
106 uno_Interface
* pUnoI
,
107 typelib_InterfaceTypeDescription
* pTD
,
108 const OUString
& oid
)
109 :RealProxy(MarshalByRefObject::typeid),
111 m_oid(mapUnoString(oid
.pData
)),
112 m_sTypeName(m_system_Object_String
)
115 // create the list that holds all UnoInterfaceInfos
116 m_listIfaces
= gcnew
ArrayList(10);
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
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: "),
142 sd::Trace::WriteLine( mapUnoString(_sInterfaces
));
143 rtl_uString_release(_sInterfaces
);
145 //m_bridge is unmanaged, therefore we can access it in this finalizer
146 CliEnvHolder::g_cli_env
->revokeInterface(m_oid
);
150 System::Object
^ UnoInterfaceProxy::create(
152 uno_Interface
* pUnoI
,
153 typelib_InterfaceTypeDescription
* pTD
,
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
));
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
^>(
175 if (typelib_typedescription_equals(
176 reinterpret_cast<typelib_TypeDescription
*>(info
->m_typeDesc
),
177 reinterpret_cast<typelib_TypeDescription
*>(pTd
)))
182 OUString
oid(mapCliString(m_oid
));
183 (*m_bridge
->m_uno_env
->registerInterface
)(
184 m_bridge
->m_uno_env
, reinterpret_cast< void ** >( &pUnoI
),
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
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
);
204 System::Threading::Monitor::Exit(this);
210 bool UnoInterfaceProxy::CanCastTo(System::Type
^ fromType
,
213 if (fromType
== System::Object::typeid) // trivial case
216 System::Threading::Monitor::Enter(this);
219 if (nullptr != findInfo( fromType
)) // proxy supports demanded interface
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);
235 System::Object
^ pException
= nullptr;
237 pAny
= static_cast<uno::Any
^>(
241 ((typelib_InterfaceMethodTypeDescription
*)
242 membertd
.get())->pReturnTypeRef
,
244 ((typelib_InterfaceMethodTypeDescription
*)
245 membertd
.get())->pParams
,
246 args
, nullptr, &pException
) );
248 // handle regular exception from target
250 nullptr == pException
,
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
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
) );
282 catch (BridgeRuntimeError
& e
)
284 (void) e
; // avoid warning
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"
295 msg
= System::String::Concat(msg
, e
->Message
);
298 mapCliString(msg
), RTL_TEXTENCODING_UTF8
).getStr() );
303 "An unexpected native C++ exception occurred in "
304 "UnoInterfaceProxy::CanCastTo()" );
308 System::Threading::Monitor::Exit(this);
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
))
326 OSL_ASSERT(args
->Length
== 1);
327 srrp::RealProxy
^ rProxy
= srr::RemotingServices::GetRealProxy(args
[0]);
331 UnoInterfaceProxy
^ unoProxy
=
332 dynamic_cast<UnoInterfaceProxy
^>(rProxy
);
335 bool b
= m_oid
->Equals(unoProxy
->getOid());
342 //no proxy or not our proxy, therefore Equals must be false
346 else if (m_GetHashCode_String
->Equals(sMethod
))
348 // Object.GetHashCode
349 int nHash
= m_oid
->GetHashCode();
352 else if (m_GetType_String
->Equals(sMethod
))
355 retMethod
= System::Object::typeid;
357 else if (m_ToString_String
->Equals(sMethod
))
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();
368 //Either Object has new functions or a protected method was called
369 //which should not be possible
372 srrm::IMessage
^ retVal
= gcnew
srrm::ReturnMessage(
373 retMethod
, gcnew array
<System::Object
^>(0), 0, context
, mcm
);
377 UnoInterfaceInfo
^ UnoInterfaceProxy::findInfo( ::System::Type
^ type
)
379 for (int i
= 0; i
< m_numUnoIfaces
; i
++)
381 UnoInterfaceInfo
^ tmpInfo
= static_cast<UnoInterfaceInfo
^>(
383 if (type
->IsAssignableFrom(tmpInfo
->m_type
))
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
);
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
);
445 sal_Int32 offset
= usTypeName
.indexOf( ':' ) + 2;
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
*)
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
,
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
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
*)
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
,
504 nullptr, nullptr, &pExc
);
505 return constructReturnMessage(cli_ret
, nullptr, NULL
,
508 else if ('s' == usMethodName
[0])
510 TypeDescr
member_td( member_type
);
511 typelib_InterfaceAttributeTypeDescription
* attribute_td
=
512 (typelib_InterfaceAttributeTypeDescription
*)
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;
526 info
->m_unoI
, member_td
.get(),
527 cppu::UnoType
<void>::get().getTypeLibType(),
528 1, ¶m
, args
, nullptr, &pExc
);
529 return constructReturnMessage(nullptr, nullptr, NULL
,
534 return constructReturnMessage(nullptr, nullptr, NULL
,
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"
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
);
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(
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
);
596 retVal
= gcnew
srrm::ReturnMessage(
597 dynamic_cast<System::Exception
^>(exc
), mcm
);
601 sc::IDictionary
^ props
= msg
->Properties
;
602 srrm::LogicalCallContext
^ context
=
603 static_cast<srrm::LogicalCallContext
^>(
604 props
[m_CallContextString
]);
608 //build the array of out parameters, allocate max length
609 array
<System::Object
^>^ arOut
= gcnew array
<System::Object
^>(mtd
->nParams
);
611 for (int i
= 0; i
< mtd
->nParams
; i
++)
613 if (mtd
->pParams
[i
].bOut
)
619 retVal
= gcnew
srrm::ReturnMessage(cliReturn
, arOut
, nOut
,
624 // Attribute (getXXX)
625 retVal
= gcnew
srrm::ReturnMessage(cliReturn
, nullptr, 0,
633 CliProxy::CliProxy(Bridge
const* bridge
, System::Object
^ cliI
,
634 typelib_TypeDescription
const* td
,
635 const OUString
& usOid
):
639 m_unoType(const_cast<typelib_TypeDescription
*>(td
)),
641 m_oid(mapUnoString(usOid
.pData
)),
642 m_nInheritedInterfaces(0)
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());
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
));
661 void CliProxy::makeMethodInfos()
663 #if OSL_DEBUG_LEVEL >= 2
664 System::Object
^ cliI
;
670 if (m_type
->IsInterface
== false)
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
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
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
700 // but it is Type*[] instead. Bug in the framework?
701 System::Type
^ objType
= m_cliI
->GetType();
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
];
754 return m_arMethodInfos
[cliPos
];
756 //create the method function name
757 System::String
^ sMethodName
= mapUnoString(usMethodName
.pData
);
763 sMethodName
= System::String::Concat(
764 const_cast<System::String
^>(Constants::sAttributeSet
),
768 sMethodName
= System::String::Concat(
769 const_cast<System::String
^>(Constants::sAttributeGet
),
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
;
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
))
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
];
806 System::Threading::Monitor::Exit(m_arUnoPosToCliPos
);
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"),
821 CliEnvHolder::g_cli_env
->revokeInterface(m_oid
, mapUnoType(m_unoType
.get()));
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
)(
836 reinterpret_cast<void**>(&proxy
),
838 ousOid
.pData
, (typelib_InterfaceTypeDescription
*) pTD
);
839 //register original interface
840 CliEnvHolder::g_cli_env
->registerInterface(cliI
, mapUnoString(ousOid
.pData
),
847 void SAL_CALL
CliProxy::uno_DispatchMethod(
848 struct _uno_Interface
*,
849 const struct _typelib_TypeDescription
*,
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
);
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
881 (*m_bridge
->m_uno_env
->revokeInterface
)(
882 m_bridge
->m_uno_env
, const_cast< CliProxy
* >( this ) );
889 void SAL_CALL
cli_proxy_free( uno_ExtEnvironment
*, void * proxy
)
892 cli_uno::CliProxy
* cliProxy
= reinterpret_cast<
893 cli_uno::CliProxy
* >( proxy
);
899 void SAL_CALL
cli_proxy_acquire( uno_Interface
* pUnoI
)
902 CliProxy
const * cliProxy
= static_cast< CliProxy
const * >( pUnoI
);
907 void SAL_CALL
cli_proxy_release( uno_Interface
* pUnoI
)
910 CliProxy
* cliProxy
= static_cast< CliProxy
* >( pUnoI
);
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
)
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();
937 member_pos
< iface_td
->nAllMembers
,
938 "### member pos out of range!" );
939 sal_Int32 function_pos
=
940 iface_td
->pMapMemberIndexToFunctionIndex
[ member_pos
];
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
)
950 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
,
951 usAttrName
, CliProxy::MK_GET
);
955 ((typelib_InterfaceAttributeTypeDescription
*)member_td
)
958 uno_ret
, 0, uno_exc
);
960 else // is setter method
962 OUString
const& usAttrName
= *(rtl_uString
**) &
963 ((typelib_InterfaceMemberTypeDescription
*) member_td
)
965 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
+ 1,
966 usAttrName
, CliProxy::MK_SET
);
967 typelib_MethodParameter param
;
969 ((typelib_InterfaceAttributeTypeDescription
*)member_td
)
971 param
.bIn
= sal_True
;
972 param
.bOut
= sal_False
;
976 // set follows get method
978 0 /* indicates void return */, ¶m
, 1,
979 0, uno_args
, uno_exc
);
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();
990 member_pos
< iface_td
->nAllMembers
,
991 "### member pos out of range!" );
992 sal_Int32 function_pos
=
993 iface_td
->pMapMemberIndexToFunctionIndex
[ member_pos
];
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
**>(
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
)(
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
1027 CliEnvHolder::g_cli_env
->getObjectIdentifier(
1029 OSL_ENSURE(usOid
.equals( proxy
->m_usOid
),
1030 "### different oids!");
1032 uno_Interface
* pUnoI
= bridge
->map_cli2uno(
1033 proxy
->m_cliI
, demanded_td
.get() );
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
1048 reinterpret_cast< uno_Any
* >( uno_ret
),
1049 &pInterface
, demanded_td
.get(), 0 );
1050 (*pInterface
->release
)( pInterface
);
1055 case 1: // acquire this proxy
1056 cli_proxy_acquire(proxy
);
1059 case 2: // release this proxy
1060 cli_proxy_release(proxy
);
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
)
1071 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
,
1072 usMethodName
, CliProxy::MK_METHOD
);
1076 method_td
->pReturnTypeRef
, method_td
->pParams
,
1078 uno_ret
, uno_args
, uno_exc
);
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: */