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 "com/sun/star/uno/RuntimeException.hpp"
23 #include "osl/mutex.hxx"
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
;
42 using ::rtl::OUString
;
43 using ::rtl::OUStringToOString
;
45 using ::rtl::OUStringBuffer
;
48 //------------------------------------------------------------------------------
49 void SAL_CALL
cli_proxy_free( uno_ExtEnvironment
* env
, void * proxy
)
51 //------------------------------------------------------------------------------
52 void SAL_CALL
cli_proxy_acquire( uno_Interface
* pUnoI
)
54 //------------------------------------------------------------------------------
55 void SAL_CALL
cli_proxy_release( uno_Interface
* pUnoI
)
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
)
69 UnoInterfaceInfo::UnoInterfaceInfo(Bridge
const * bridge
, uno_Interface
* unoI
,
70 typelib_InterfaceTypeDescription
* td
):
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
);
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
);
102 m_unoI
->release(m_unoI
);
103 typelib_typedescription_release(
104 reinterpret_cast<typelib_TypeDescription
*>(m_typeDesc
));
107 UnoInterfaceProxy::UnoInterfaceProxy(
109 uno_Interface
* pUnoI
,
110 typelib_InterfaceTypeDescription
* pTD
,
111 const OUString
& oid
)
112 :RealProxy(MarshalByRefObject::typeid),
114 m_oid(mapUnoString(oid
.pData
)),
115 m_sTypeName(m_system_Object_String
)
118 // create the list that holds all UnoInterfaceInfos
119 m_listIfaces
= gcnew
ArrayList(10);
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
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: "),
140 sd::Trace::WriteLine( mapUnoString(_sInterfaces
));
141 rtl_uString_release(_sInterfaces
);
143 //m_bridge is unmanaged, therefore we can access it in this finalizer
144 CliEnvHolder::g_cli_env
->revokeInterface(m_oid
);
149 System::Object
^ UnoInterfaceProxy::create(
151 uno_Interface
* pUnoI
,
152 typelib_InterfaceTypeDescription
* pTD
,
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
));
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
^>(
174 #if OSL_DEBUG_LEVEL > 1
178 reinterpret_cast<typelib_TypeDescription
*>(info
->m_typeDesc
) );
180 reinterpret_cast<typelib_TypeDescription
*>(pTd
) );
182 if (typelib_typedescription_equals(
183 reinterpret_cast<typelib_TypeDescription
*>(info
->m_typeDesc
),
184 reinterpret_cast<typelib_TypeDescription
*>(pTd
)))
189 OUString
oid(mapCliString(m_oid
));
190 (*m_bridge
->m_uno_env
->registerInterface
)(
191 m_bridge
->m_uno_env
, reinterpret_cast< void ** >( &pUnoI
),
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
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
);
217 System::Threading::Monitor::Exit(this);
223 bool UnoInterfaceProxy::CanCastTo(System::Type
^ fromType
,
226 if (fromType
== System::Object::typeid) // trivial case
229 System::Threading::Monitor::Enter(this);
232 if (nullptr != findInfo( fromType
)) // proxy supports demanded interface
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);
248 System::Object
^ pException
= nullptr;
250 pAny
= static_cast<uno::Any
^>(
254 ((typelib_InterfaceMethodTypeDescription
*)
255 membertd
.get())->pReturnTypeRef
,
257 ((typelib_InterfaceMethodTypeDescription
*)
258 membertd
.get())->pParams
,
259 args
, nullptr, &pException
) );
261 // handle regular exception from target
263 nullptr == pException
,
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
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
) );
295 catch (BridgeRuntimeError
& e
)
297 (void) e
; // avoid warning
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"
308 msg
= System::String::Concat(msg
, e
->Message
);
311 mapCliString(msg
), RTL_TEXTENCODING_UTF8
).getStr() );
316 "An unexpected native C++ exception occurred in "
317 "UnoInterfaceProxy::CanCastTo()" );
321 System::Threading::Monitor::Exit(this);
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
))
339 OSL_ASSERT(args
->Length
== 1);
340 srrp::RealProxy
^ rProxy
= srr::RemotingServices::GetRealProxy(args
[0]);
344 UnoInterfaceProxy
^ unoProxy
=
345 dynamic_cast<UnoInterfaceProxy
^>(rProxy
);
348 bool b
= m_oid
->Equals(unoProxy
->getOid());
355 //no proxy or not our proxy, therefore Equals must be false
359 else if (m_GetHashCode_String
->Equals(sMethod
))
361 // Object.GetHashCode
362 int nHash
= m_oid
->GetHashCode();
365 else if (m_GetType_String
->Equals(sMethod
))
368 retMethod
= System::Object::typeid;
370 else if (m_ToString_String
->Equals(sMethod
))
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();
381 //Either Object has new functions or a protected method was called
382 //which should not be possible
385 srrm::IMessage
^ retVal
= gcnew
srrm::ReturnMessage(
386 retMethod
, gcnew array
<System::Object
^>(0), 0, context
, mcm
);
390 UnoInterfaceInfo
^ UnoInterfaceProxy::findInfo( ::System::Type
^ type
)
392 for (int i
= 0; i
< m_numUnoIfaces
; i
++)
394 UnoInterfaceInfo
^ tmpInfo
= static_cast<UnoInterfaceInfo
^>(
396 if (type
->IsAssignableFrom(tmpInfo
->m_type
))
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
);
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
);
458 sal_Int32 offset
= usTypeName
.indexOf( ':' ) + 2;
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
*)
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
,
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
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
*)
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
,
517 nullptr, nullptr, &pExc
);
518 return constructReturnMessage(cli_ret
, nullptr, NULL
,
521 else if ('s' == usMethodName
[0])
523 TypeDescr
member_td( member_type
);
524 typelib_InterfaceAttributeTypeDescription
* attribute_td
=
525 (typelib_InterfaceAttributeTypeDescription
*)
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;
539 info
->m_unoI
, member_td
.get(),
540 ::getCppuVoidType().getTypeLibType(),
541 1, ¶m
, args
, nullptr, &pExc
);
542 return constructReturnMessage(nullptr, nullptr, NULL
,
547 return constructReturnMessage(nullptr, nullptr, NULL
,
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 "
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"
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
);
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(
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
);
615 retVal
= gcnew
srrm::ReturnMessage(
616 dynamic_cast<System::Exception
^>(exc
), mcm
);
620 sc::IDictionary
^ props
= msg
->Properties
;
621 srrm::LogicalCallContext
^ context
=
622 static_cast<srrm::LogicalCallContext
^>(
623 props
[m_CallContextString
]);
627 //build the array of out parameters, allocate max length
628 array
<System::Object
^>^ arOut
= gcnew array
<System::Object
^>(mtd
->nParams
);
630 for (int i
= 0; i
< mtd
->nParams
; i
++)
632 if (mtd
->pParams
[i
].bOut
)
638 retVal
= gcnew
srrm::ReturnMessage(cliReturn
, arOut
, nOut
,
643 // Attribute (getXXX)
644 retVal
= gcnew
srrm::ReturnMessage(cliReturn
, nullptr, 0,
651 //################################################################################
652 CliProxy::CliProxy(Bridge
const* bridge
, System::Object
^ cliI
,
653 typelib_TypeDescription
const* td
,
654 const rtl::OUString
& usOid
):
658 m_unoType(const_cast<typelib_TypeDescription
*>(td
)),
660 m_oid(mapUnoString(usOid
.pData
)),
661 m_nInheritedInterfaces(0)
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());
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
));
680 void CliProxy::makeMethodInfos()
682 #if OSL_DEBUG_LEVEL >= 2
683 System::Object
* cliI
;
689 if (m_type
->IsInterface
== false)
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
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
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
;
726 //fill m_arMethodInfos with the mappings
727 // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
729 // but it is Type*[] instead. Bug in the framework?
730 System::Type
^ objType
= m_cliI
->GetType();
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
;
794 //deduct 3 for XInterface methods
795 nUnoFunctionPos
-= 3;
796 System::Threading::Monitor::Enter(m_arUnoPosToCliPos
);
799 int cliPos
= m_arUnoPosToCliPos
[nUnoFunctionPos
];
801 return m_arMethodInfos
[cliPos
];
803 //create the method function name
804 System::String
^ sMethodName
= mapUnoString(usMethodName
.pData
);
810 sMethodName
= System::String::Concat(
811 const_cast<System::String
^>(Constants::sAttributeSet
),
815 sMethodName
= System::String::Concat(
816 const_cast<System::String
^>(Constants::sAttributeGet
),
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
;
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
))
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
];
858 System::Threading::Monitor::Exit(m_arUnoPosToCliPos
);
864 CliProxy::~CliProxy()
866 #if OSL_DEBUG_LEVEL >= 2
867 sd::Trace::WriteLine(System::String::Format(
869 S
"cli uno bridge: Destroying proxy for cli object, "
870 S
"id:\n\t{0}\n\t{1}\n"),
873 CliEnvHolder::g_cli_env
->revokeInterface(m_oid
, mapUnoType(m_unoType
.get()));
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
)(
888 reinterpret_cast<void**>(&proxy
),
890 ousOid
.pData
, (typelib_InterfaceTypeDescription
*) pTD
);
891 //register original interface
892 CliEnvHolder::g_cli_env
->registerInterface(cliI
, mapUnoString(ousOid
.pData
),
900 void SAL_CALL
CliProxy::uno_DispatchMethod(
901 struct _uno_Interface
*,
902 const struct _typelib_TypeDescription
*,
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
);
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
934 (*m_bridge
->m_uno_env
->revokeInterface
)(
935 m_bridge
->m_uno_env
, const_cast< CliProxy
* >( this ) );
944 void SAL_CALL
cli_proxy_free( uno_ExtEnvironment
*, void * proxy
)
947 cli_uno::CliProxy
* cliProxy
= reinterpret_cast<
948 cli_uno::CliProxy
* >( proxy
);
954 void SAL_CALL
cli_proxy_acquire( uno_Interface
* pUnoI
)
957 CliProxy
const * cliProxy
= static_cast< CliProxy
const * >( pUnoI
);
960 //-----------------------------------------------------------------------------
962 void SAL_CALL
cli_proxy_release( uno_Interface
* pUnoI
)
965 CliProxy
* cliProxy
= static_cast< CliProxy
* >( pUnoI
);
969 //------------------------------------------------------------------------------
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
)
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();
992 member_pos
< iface_td
->nAllMembers
,
993 "### member pos out of range!" );
994 sal_Int32 function_pos
=
995 iface_td
->pMapMemberIndexToFunctionIndex
[ member_pos
];
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
)
1005 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
,
1006 usAttrName
, CliProxy::MK_GET
);
1010 ((typelib_InterfaceAttributeTypeDescription
*)member_td
)
1011 ->pAttributeTypeRef
,
1013 uno_ret
, 0, uno_exc
);
1015 else // is setter method
1017 OUString
const& usAttrName
= *(rtl_uString
**) &
1018 ((typelib_InterfaceMemberTypeDescription
*) member_td
)
1020 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
+ 1,
1021 usAttrName
, CliProxy::MK_SET
);
1022 typelib_MethodParameter param
;
1024 ((typelib_InterfaceAttributeTypeDescription
*)member_td
)
1025 ->pAttributeTypeRef
;
1026 param
.bIn
= sal_True
;
1027 param
.bOut
= sal_False
;
1031 // set follows get method
1033 0 /* indicates void return */, ¶m
, 1,
1034 0, uno_args
, uno_exc
);
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();
1045 member_pos
< iface_td
->nAllMembers
,
1046 "### member pos out of range!" );
1047 sal_Int32 function_pos
=
1048 iface_td
->pMapMemberIndexToFunctionIndex
[ member_pos
];
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
**>(
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
)(
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
1082 CliEnvHolder::g_cli_env
->getObjectIdentifier(
1084 OSL_ENSURE(usOid
.equals( proxy
->m_usOid
),
1085 "### different oids!");
1087 uno_Interface
* pUnoI
= bridge
->map_cli2uno(
1088 proxy
->m_cliI
, demanded_td
.get() );
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
1103 reinterpret_cast< uno_Any
* >( uno_ret
),
1104 &pInterface
, demanded_td
.get(), 0 );
1105 (*pInterface
->release
)( pInterface
);
1110 case 1: // acquire this proxy
1111 cli_proxy_acquire(proxy
);
1114 case 2: // release this proxy
1115 cli_proxy_release(proxy
);
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
)
1126 sr::MethodInfo
^ info
= proxy
->getMethodInfo(function_pos
,
1127 usMethodName
, CliProxy::MK_METHOD
);
1131 method_td
->pReturnTypeRef
, method_td
->pParams
,
1133 uno_ret
, uno_args
, uno_exc
);
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());
1167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */