xref: /AOO41X/main/cli_ure/source/uno_bridge/cli_proxy.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cli_ure.hxx"
30 #include "typelib/typedescription.h"
31 #include "rtl/ustrbuf.hxx"
32 #include "com/sun/star/uno/RuntimeException.hpp"
33 #include "osl/mutex.hxx"
34 #include "cli_proxy.h"
35 #include "cli_base.h"
36 #include "cli_bridge.h"
37 
38 #using <mscorlib.dll>
39 #using <cli_ure.dll>
40 #using <cli_uretypes.dll>
41 
42 namespace sr = System::Reflection;
43 namespace st = System::Text;
44 namespace sre = System::Reflection::Emit;
45 namespace sc = System::Collections;
46 namespace srrm = System::Runtime::Remoting::Messaging;
47 namespace srr = System::Runtime::Remoting;
48 namespace srrp = System::Runtime::Remoting::Proxies;
49 namespace sri = System::Runtime::InteropServices;
50 namespace sd = System::Diagnostics;
51 namespace css = com::sun::star;
52 namespace ucss = unoidl::com::sun::star;
53 
54 using namespace cli_uno;
55 using namespace rtl;
56 extern "C"
57 {
58 //------------------------------------------------------------------------------
59 void SAL_CALL cli_proxy_free( uno_ExtEnvironment * env, void * proxy )
60     SAL_THROW_EXTERN_C();
61 //------------------------------------------------------------------------------
62 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
63     SAL_THROW_EXTERN_C();
64 //------------------------------------------------------------------------------
65 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
66     SAL_THROW_EXTERN_C();
67 //------------------------------------------------------------------------------
68 void SAL_CALL cli_proxy_dispatch(
69     uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
70     void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
71     SAL_THROW_EXTERN_C();
72 
73 
74 }
75 
76 namespace cli_uno
77 {
78 
79 UnoInterfaceInfo::UnoInterfaceInfo(Bridge const * bridge, uno_Interface* unoI,
80                                    typelib_InterfaceTypeDescription* td):
81 
82     m_unoI(unoI),
83     m_typeDesc(td),
84     m_bridge(bridge)
85 {
86     m_bridge->acquire();
87     m_type = mapUnoType(reinterpret_cast<typelib_TypeDescription*>(td));
88     m_unoI->acquire(m_unoI);
89     typelib_typedescription_acquire(&m_typeDesc->aBase);
90    	if ( ! m_typeDesc->aBase.bComplete)
91     {
92         typelib_TypeDescription* _pt = &m_typeDesc->aBase;
93 		sal_Bool bComplete = ::typelib_typedescription_complete( & _pt);
94         if( ! bComplete)
95         {
96             OUStringBuffer buf( 128 );
97             buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
98                                  "cannot make type complete: ") );
99             buf.append( *reinterpret_cast< OUString const * >(
100                             & m_typeDesc->aBase.pTypeName));
101             throw BridgeRuntimeError(buf.makeStringAndClear());
102         }
103     }
104 }
105 UnoInterfaceInfo::~UnoInterfaceInfo()
106 {
107     //accessing unmanaged objects is ok.
108    m_bridge->m_uno_env->revokeInterface(
109             m_bridge->m_uno_env, m_unoI );
110    m_bridge->release();
111 
112     m_unoI->release(m_unoI);
113     typelib_typedescription_release(
114         reinterpret_cast<typelib_TypeDescription*>(m_typeDesc));
115 }
116 
117 UnoInterfaceProxy::UnoInterfaceProxy(
118     Bridge * bridge,
119     uno_Interface * pUnoI,
120     typelib_InterfaceTypeDescription* pTD,
121     const OUString& oid )
122     :RealProxy(__typeof(MarshalByRefObject)),
123      m_bridge(bridge),
124      m_oid(mapUnoString(oid.pData)),
125      m_sTypeName(m_system_Object_String)
126 {
127     m_bridge->acquire();
128     // create the list that holds all UnoInterfaceInfos
129     m_listIfaces = new ArrayList(10);
130     m_numUnoIfaces = 0;
131     m_listAdditionalProxies = new ArrayList();
132     m_nlistAdditionalProxies = 0;
133     //put the information of the first UNO interface into the arraylist
134 #if OSL_DEBUG_LEVEL >= 2
135     _numInterfaces = 0;
136     _sInterfaces = NULL;
137 #endif
138     addUnoInterface(pUnoI, pTD);
139 
140 }
141 
142 UnoInterfaceProxy::~UnoInterfaceProxy()
143 {
144 #if OSL_DEBUG_LEVEL >= 2
145     sd::Trace::WriteLine(System::String::Format(
146                new System::String(S"cli uno bridge: Destroying proxy "
147                S"for UNO object, OID: \n\t{0} \n\twith uno interfaces: "),
148                m_oid));
149 
150     sd::Trace::WriteLine( mapUnoString(_sInterfaces));
151     rtl_uString_release(_sInterfaces);
152 #endif
153     //m_bridge is unmanaged, therefore we can access it in this finalizer
154 	CliEnvHolder::g_cli_env->revokeInterface(m_oid);
155     m_bridge->release();
156 }
157 
158 
159 System::Object* UnoInterfaceProxy::create(
160     Bridge * bridge,
161     uno_Interface * pUnoI,
162     typelib_InterfaceTypeDescription* pTD,
163     const OUString& oid)
164 {
165     UnoInterfaceProxy* proxyHandler=
166         new UnoInterfaceProxy(bridge, pUnoI, pTD, oid);
167     System::Object* proxy= proxyHandler->GetTransparentProxy();
168 	CliEnvHolder::g_cli_env->registerInterface(proxy, mapUnoString(oid.pData));
169     return proxy;
170 }
171 
172 
173 void UnoInterfaceProxy::addUnoInterface(uno_Interface* pUnoI,
174                                         typelib_InterfaceTypeDescription* pTd)
175 {
176     sc::IEnumerator* enumInfos = m_listIfaces->GetEnumerator();
177     System::Threading::Monitor::Enter(this);
178     try
179     {
180         while (enumInfos->MoveNext())
181         {
182             UnoInterfaceInfo* info = static_cast<UnoInterfaceInfo*>(
183                 enumInfos->Current);
184 #if OSL_DEBUG_LEVEL > 1
185             System::Type * t1;
186             System::Type * t2;
187             t1 = mapUnoType(
188                 reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc) );
189             t2 = mapUnoType(
190                 reinterpret_cast<typelib_TypeDescription*>(pTd) );
191 #endif
192             if (typelib_typedescription_equals(
193                reinterpret_cast<typelib_TypeDescription*>(info->m_typeDesc),
194                reinterpret_cast<typelib_TypeDescription*>(pTd)))
195             {
196                 return;
197             }
198         }
199         OUString oid(mapCliString(m_oid));
200         (*m_bridge->m_uno_env->registerInterface)(
201             m_bridge->m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
202             oid.pData, pTd);
203         //This proxy does not contain the uno_Interface. Add it.
204         m_listIfaces->Add(new UnoInterfaceInfo(m_bridge, pUnoI, pTd));
205         m_numUnoIfaces = m_listIfaces->Count;
206 #if OSL_DEBUG_LEVEL >= 2
207         System::String * sInterfaceName = static_cast<UnoInterfaceInfo*>(
208             m_listIfaces->get_Item(m_numUnoIfaces - 1))->m_type->FullName;
209         sd::Trace::WriteLine(System::String::Format(
210              new System::String(S"cli uno bridge: Creating proxy for uno object, "
211                  S"id:\n\t{0}\n\t{1}"), m_oid, sInterfaceName));
212         // add to the string that contains all interface names
213          _numInterfaces ++;
214          OUStringBuffer buf(512);
215         buf.appendAscii("\t");
216         buf.append( OUString::valueOf((sal_Int32)_numInterfaces));
217         buf.appendAscii(". ");
218         buf.append(mapCliString(sInterfaceName));
219         buf.appendAscii("\n");
220         OUString _sNewInterface = buf.makeStringAndClear();
221         rtl_uString * __pin * pp_sInterfaces = & _sInterfaces;
222         rtl_uString_newConcat( pp_sInterfaces, * pp_sInterfaces,
223                                _sNewInterface.pData);
224 #endif
225     }
226     __finally {
227         System::Threading::Monitor::Exit(this);
228     }
229 }
230 
231 
232 // IRemotingTypeInfo
233 bool UnoInterfaceProxy::CanCastTo(System::Type* fromType,
234                                   System::Object*)
235 {
236     if (fromType == __typeof(System::Object)) // trivial case
237         return true;
238 
239     System::Threading::Monitor::Enter(this);
240     try
241     {
242         if (0 != findInfo( fromType )) // proxy supports demanded interface
243             return true;
244 
245         //query an uno interface for the required type
246 
247         // we use the first interface in the list (m_listIfaces) to make
248         // the queryInterface call
249         UnoInterfaceInfo* info =
250             static_cast<UnoInterfaceInfo*>(m_listIfaces->get_Item(0));
251         css::uno::TypeDescription membertd(
252             reinterpret_cast<typelib_InterfaceTypeDescription*>(
253                 info->m_typeDesc)->ppAllMembers[0]);
254         System::Object *args[] = new System::Object*[1];
255 
256         args[0] = fromType;
257         __box uno::Any  * pAny;
258         System::Object* pException = NULL;
259 
260         pAny= static_cast<__box uno::Any *>(
261             m_bridge->call_uno(
262                 info->m_unoI,
263                 membertd.get(),
264                 ((typelib_InterfaceMethodTypeDescription*)
265                  membertd.get())->pReturnTypeRef,
266                 1,
267                 ((typelib_InterfaceMethodTypeDescription*)
268                  membertd.get())->pParams,
269                 args, NULL, &pException) );
270 
271         // handle regular exception from target
272         OSL_ENSURE(
273             0 == pException,
274             OUStringToOString(
275                 mapCliString( pException->ToString()),
276                 RTL_TEXTENCODING_UTF8 ).getStr() );
277 
278         if (pAny->Type != __typeof (void)) // has value?
279         {
280             if (0 != findInfo( fromType ))
281             {
282                 // proxy now supports demanded interface
283                 return true;
284             }
285 
286             // via aggregation: it is possible that queryInterface() returns
287             //                  and interface with a different oid.
288             //                  That way, this type is supported for the CLI
289             //                  interpreter (CanCastTo() returns true)
290             ::System::Object * obj = pAny->Value;
291             OSL_ASSERT( srr::RemotingServices::IsTransparentProxy( obj ) );
292             if (srr::RemotingServices::IsTransparentProxy( obj ))
293             {
294                 UnoInterfaceProxy * proxy =
295                     static_cast< UnoInterfaceProxy * >(
296                         srr::RemotingServices::GetRealProxy( obj ) );
297                 OSL_ASSERT( 0 != proxy->findInfo( fromType ) );
298                 m_listAdditionalProxies->Add( proxy );
299                 m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
300                 OSL_ASSERT( 0 != findInfo( fromType ) );
301                 return true;
302             }
303         }
304     }
305     catch (BridgeRuntimeError& e)
306     {
307         (void) e; // avoid warning
308         OSL_ENSURE(
309             0, OUStringToOString(
310                 e.m_message, RTL_TEXTENCODING_UTF8 ).getStr() );
311     }
312     catch (System::Exception* e)
313     {
314         System::String* msg= new System::String(
315             S"An unexpected CLI exception occurred in "
316             S"UnoInterfaceProxy::CanCastTo().  Original"
317             S"message: \n");
318         msg= System::String::Concat(msg, e->get_Message());
319         OSL_ENSURE(
320             0, OUStringToOString(
321                 mapCliString(msg), RTL_TEXTENCODING_UTF8 ).getStr() );
322     }
323     catch (...)
324     {
325         OSL_ENSURE(
326             0, "An unexpected native C++ exception occurred in "
327             "UnoInterfaceProxy::CanCastTo()" );
328     }
329     __finally
330     {
331         System::Threading::Monitor::Exit(this);
332     }
333     return false;
334 }
335 
336 srrm::IMessage* UnoInterfaceProxy::invokeObject(
337     sc::IDictionary* props,
338     srrm::LogicalCallContext* context,
339     srrm::IMethodCallMessage* mcm)
340 {
341     System::Object* retMethod = 0;
342     System::String* sMethod = static_cast<System::String*>
343         (props->get_Item(m_methodNameString));
344     System::Object* args[] = static_cast<System::Object*[]>(
345         props->get_Item(m_ArgsString));
346     if (m_Equals_String->Equals(sMethod))
347     {
348         // Object.Equals
349         OSL_ASSERT(args->get_Length() == 1);
350         srrp::RealProxy* rProxy = srr::RemotingServices::GetRealProxy(args[0]);
351         bool bDone = false;
352         if (rProxy)
353         {
354             UnoInterfaceProxy* unoProxy =
355                 dynamic_cast<UnoInterfaceProxy*>(rProxy);
356             if (unoProxy)
357             {
358                 bool b = m_oid->Equals(unoProxy->getOid());
359                 retMethod = __box(b);
360                 bDone = true;
361             }
362         }
363         if (bDone == false)
364         {
365             //no proxy or not our proxy, therefore Equals must be false
366             retMethod = __box(false);
367         }
368     }
369     else if (m_GetHashCode_String->Equals(sMethod))
370     {
371         // Object.GetHashCode
372         int nHash = m_oid->GetHashCode();
373         retMethod = __box(nHash);
374     }
375     else if (m_GetType_String->Equals(sMethod))
376     {
377         // Object.GetType
378         retMethod = __typeof(System::Object);
379     }
380     else if (m_ToString_String->Equals(sMethod))
381     {
382         // Object.ToString
383         st::StringBuilder* sb = new st::StringBuilder(256);
384 // 				sb->AppendFormat(S"Uno object proxy. Implemented interface: {0}"
385 // 					S". OID: {1}", m_type->ToString(), m_oid);
386         sb->AppendFormat(S"Uno object proxy. OID: {0}", m_oid);
387         retMethod = sb->ToString();
388     }
389     else
390     {
391         //Either Object has new functions or a protected method was called
392         //which should not be possible
393         OSL_ASSERT(0);
394     }
395     srrm::IMessage* retVal= new srrm::ReturnMessage(
396         retMethod, new System::Object*[0], 0, context, mcm);
397     return retVal;
398 }
399 
400 UnoInterfaceInfo * UnoInterfaceProxy::findInfo( ::System::Type * type )
401 {
402     for (int i = 0; i < m_numUnoIfaces; i++)
403     {
404         UnoInterfaceInfo* tmpInfo = static_cast<UnoInterfaceInfo*>(
405             m_listIfaces->get_Item(i));
406         if (type->IsAssignableFrom(tmpInfo->m_type))
407             return tmpInfo;
408     }
409     for ( int i = 0; i < m_nlistAdditionalProxies; ++i )
410     {
411         UnoInterfaceProxy * proxy =
412             static_cast< UnoInterfaceProxy * >(
413                 m_listAdditionalProxies->get_Item( i ) );
414         UnoInterfaceInfo * info = proxy->findInfo( type );
415         if (0 != info)
416             return info;
417     }
418     return 0;
419 }
420 
421 srrm::IMessage* UnoInterfaceProxy::Invoke(srrm::IMessage* callmsg)
422 {
423     try
424     {
425         sc::IDictionary* props= callmsg->Properties;
426         srrm::LogicalCallContext* context=
427             static_cast<srrm::LogicalCallContext*>(
428                 props->get_Item(m_CallContextString));
429         srrm::IMethodCallMessage* mcm=
430             static_cast<srrm::IMethodCallMessage*>(callmsg);
431 
432         //Find out which UNO interface is being called
433         System::String* sTypeName = static_cast<System::String*>(
434             props->get_Item(m_typeNameString));
435         sTypeName = sTypeName->Substring(0, sTypeName->IndexOf(','));
436 
437 		// Special Handling for System.Object methods
438         if(sTypeName->IndexOf(m_system_Object_String) != -1)
439         {
440             return invokeObject(props, context, mcm);
441         }
442 
443         System::Type* typeBeingCalled = loadCliType(sTypeName);
444         UnoInterfaceInfo* info = findInfo( typeBeingCalled );
445         OSL_ASSERT( 0 != info );
446 
447         // ToDo do without string conversion, a OUString is not needed here
448         // get the type description of the call
449         OUString usMethodName(mapCliString(static_cast<System::String*>(
450                  props->get_Item(m_methodNameString))));
451         typelib_TypeDescriptionReference ** ppAllMembers =
452             info->m_typeDesc->ppAllMembers;
453         sal_Int32 numberMembers = info->m_typeDesc->nAllMembers;
454         for ( sal_Int32 nPos = numberMembers; nPos--; )
455         {
456             typelib_TypeDescriptionReference * member_type = ppAllMembers[nPos];
457 
458             // check usMethodName against fully qualified usTypeName
459             // of member_type; usTypeName is of the form
460             //  <name> "::" <usMethodName> *(":@" <idx> "," <idx> ":" <name>)
461             OUString const & usTypeName =
462                 OUString::unacquired( & member_type->pTypeName );
463 
464 #if OSL_DEBUG_LEVEL >= 2
465 		System::String * pTypeName;
466         pTypeName = mapUnoString(usTypeName.pData);
467 #endif
468 			sal_Int32 offset = usTypeName.indexOf( ':' ) + 2;
469             OSL_ASSERT(
470                 offset >= 2 && offset < usTypeName.getLength()
471                 && usTypeName[offset - 1] == ':' );
472             sal_Int32 remainder = usTypeName.getLength() - offset;
473 
474             if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
475             {
476                 if ((usMethodName.getLength() == remainder
477                      || (usMethodName.getLength() < remainder
478                          && usTypeName[offset + usMethodName.getLength()] == ':'))
479                     && usTypeName.match(usMethodName, offset))
480                  {
481                     TypeDescr member_td( member_type );
482                     typelib_InterfaceMethodTypeDescription * method_td =
483                         (typelib_InterfaceMethodTypeDescription *)
484                         member_td.get();
485 
486                     System::Object* args[] = static_cast<System::Object*[]>(
487                         props->get_Item(m_ArgsString));
488                     System::Type* argTypes[] = static_cast<System::Type*[]>(
489                         props->get_Item(m_methodSignatureString));
490                     System::Object* pExc = NULL;
491                     System::Object * cli_ret = m_bridge->call_uno(
492                         info->m_unoI, member_td.get(),
493                         method_td->pReturnTypeRef, method_td->nParams,
494                         method_td->pParams, args, argTypes, &pExc);
495                     return constructReturnMessage(cli_ret, args, method_td,
496                                                   callmsg, pExc);
497                     break;
498                 }
499             }
500             else
501             {
502                 OSL_ASSERT( typelib_TypeClass_INTERFACE_ATTRIBUTE ==
503                             member_type->eTypeClass );
504                 if (usMethodName.getLength() > 4
505                     && (usMethodName.getLength() - 4 == remainder
506                         || (usMethodName.getLength() - 4 < remainder
507                             && usTypeName[
508                                 offset + (usMethodName.getLength() - 4)] == ':'))
509                     && usMethodName[1] == 'e' && usMethodName[2] == 't'
510                     && rtl_ustr_compare_WithLength(
511                         usTypeName.getStr() + offset,
512                         usMethodName.getLength() - 4,
513                         usMethodName.getStr() + 4,
514                         usMethodName.getLength() - 4) == 0)
515                  {
516                     if ('g' == usMethodName[0])
517                     {
518                         TypeDescr member_td( member_type );
519                         typelib_InterfaceAttributeTypeDescription * attribute_td =
520                             (typelib_InterfaceAttributeTypeDescription*)
521                             member_td.get();
522 
523                         System::Object* pExc = NULL;
524                         System::Object* cli_ret= m_bridge->call_uno(
525                             info->m_unoI, member_td.get(),
526                             attribute_td->pAttributeTypeRef,
527                             0, 0,
528                             NULL, NULL, &pExc);
529                         return constructReturnMessage(cli_ret, NULL, NULL,
530                                                       callmsg, pExc);
531                     }
532                     else if ('s' == usMethodName[0])
533                     {
534                         TypeDescr member_td( member_type );
535                         typelib_InterfaceAttributeTypeDescription * attribute_td =
536                             (typelib_InterfaceAttributeTypeDescription *)
537                             member_td.get();
538                         if (! attribute_td->bReadOnly)
539                         {
540                             typelib_MethodParameter param;
541                             param.pTypeRef = attribute_td->pAttributeTypeRef;
542                             param.bIn = sal_True;
543                             param.bOut = sal_False;
544 
545                             System::Object* args[] =
546                                 static_cast<System::Object*[]>(
547                                     props->get_Item(m_ArgsString));
548                             System::Object* pExc = NULL;
549                             m_bridge->call_uno(
550                                 info->m_unoI, member_td.get(),
551                                 ::getCppuVoidType().getTypeLibType(),
552                                 1, &param, args, NULL, &pExc);
553                             return constructReturnMessage(NULL, NULL, NULL,
554                                                           callmsg, pExc);
555                         }
556                         else
557                         {
558                             return constructReturnMessage(NULL, NULL, NULL,
559                                                           callmsg, NULL);
560                         }
561                     }
562                     break;
563                 }
564             }
565         }
566         // ToDo check if the message of the exception is not crippled
567         // the thing that should not be... no method info found!
568         OUStringBuffer buf( 64 );
569         buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
570                         "[cli_uno bridge]calling undeclared function on "
571                         "interface ") );
572         buf.append( *reinterpret_cast< OUString const * >(
573                   & ((typelib_TypeDescription *)info->m_typeDesc)->pTypeName));
574         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
575         buf.append( usMethodName );
576         throw BridgeRuntimeError( buf.makeStringAndClear() );
577     }
578     catch (BridgeRuntimeError & err)
579     {
580         srrm::IMethodCallMessage* mcm =
581             static_cast<srrm::IMethodCallMessage*>(callmsg);
582         return new srrm::ReturnMessage(new ucss::uno::RuntimeException(
583                          mapUnoString(err.m_message.pData), NULL), mcm);
584     }
585     catch (System::Exception* e)
586     {
587         st::StringBuilder * sb = new st::StringBuilder(512);
588         sb->Append(new System::String(
589             S"An unexpected CLI exception occurred in "
590             S"UnoInterfaceProxy::Invoke. Original"
591             S"message: \n"));
592         sb->Append(e->get_Message());
593         sb->Append((__wchar_t) '\n');
594         sb->Append(e->get_StackTrace());
595         srrm::IMethodCallMessage* mcm =
596             static_cast<srrm::IMethodCallMessage*>(callmsg);
597         return new srrm::ReturnMessage(new ucss::uno::RuntimeException(
598                                            sb->ToString(), NULL), mcm);
599     }
600     catch (...)
601     {
602         System::String* msg = new System::String(
603             S"An unexpected native C++ exception occurred in "
604             S"UnoInterfaceProxy::Invoke.");
605         srrm::IMethodCallMessage* mcm =
606             static_cast<srrm::IMethodCallMessage*>(callmsg);
607         return new srrm::ReturnMessage(new ucss::uno::RuntimeException(
608                                        msg, NULL), mcm);
609     }
610     return NULL;
611 }
612 /** If the argument args is NULL then this function is called for an attribute
613     method (either setXXX or getXXX).
614     For attributes the argument mtd is also NULL.
615 */
616 srrm::IMessage* UnoInterfaceProxy::constructReturnMessage(
617     System::Object* cliReturn,
618     System::Object* args[],
619     typelib_InterfaceMethodTypeDescription* mtd,
620     srrm::IMessage* msg, System::Object* exc)
621 {
622     srrm::IMessage * retVal= NULL;
623     srrm::IMethodCallMessage* mcm = static_cast<srrm::IMethodCallMessage*>(msg);
624     if (exc)
625     {
626         retVal = new srrm::ReturnMessage(
627             dynamic_cast<System::Exception*>(exc), mcm);
628     }
629     else
630     {
631         sc::IDictionary* props= msg->get_Properties();
632         srrm::LogicalCallContext* context=
633             static_cast<srrm::LogicalCallContext*>(
634             props->get_Item(m_CallContextString));
635         if (args != NULL)
636         {
637             // Method
638             //build the array of out parameters, allocate max length
639             System::Object* arOut[]= new System::Object*[mtd->nParams];
640 			int nOut = 0;
641             for (int i= 0; i < mtd->nParams; i++)
642             {
643                 if (mtd->pParams[i].bOut)
644 				{
645                     arOut[i]= args[i];
646 					nOut++;
647 				}
648             }
649             retVal= new srrm::ReturnMessage(cliReturn, arOut, nOut,
650                                             context, mcm);
651         }
652         else
653         {
654             // Attribute  (getXXX)
655             retVal= new srrm::ReturnMessage(cliReturn, NULL, 0,
656                                             context, mcm);
657         }
658     }
659     return retVal;
660 }
661 
662 //################################################################################
663 CliProxy::CliProxy(Bridge const* bridge, System::Object* cliI,
664                          typelib_TypeDescription const* td,
665                          const rtl::OUString& usOid):
666     m_ref(1),
667     m_bridge(bridge),
668     m_cliI(cliI),
669     m_unoType(const_cast<typelib_TypeDescription*>(td)),
670     m_usOid(usOid),
671     m_oid(mapUnoString(usOid.pData)),
672     m_nInheritedInterfaces(0)
673 {
674     m_bridge->acquire();
675     uno_Interface::acquire = cli_proxy_acquire;
676     uno_Interface::release = cli_proxy_release;
677     uno_Interface::pDispatcher = cli_proxy_dispatch;
678 
679     m_unoType.makeComplete();
680     m_type= mapUnoType(m_unoType.get());
681 
682     makeMethodInfos();
683 #if OSL_DEBUG_LEVEL >= 2
684     sd::Trace::WriteLine(System::String::Format(
685       new System::String(S"cli uno bridge: Creating proxy for cli object, "
686                          S"id:\n\t{0}\n\t{1}"), m_oid, m_type));
687 #endif
688 
689 }
690 
691 void CliProxy::makeMethodInfos()
692 {
693 #if OSL_DEBUG_LEVEL >= 2
694     System::Object* cliI;
695     System::Type* type;
696     cliI = m_cliI;
697     type = m_type;
698 #endif
699 
700     if (m_type->get_IsInterface() == false)
701         return;
702 	sr::MethodInfo* arThisMethods[] = m_type->GetMethods();
703     //get the inherited interfaces
704     System::Type* arInheritedIfaces[] = m_type->GetInterfaces();
705     m_nInheritedInterfaces = arInheritedIfaces->get_Length();
706     //array containing the number of methods for the interface and its
707     //inherited interfaces
708     m_arInterfaceMethodCount = new int __gc [m_nInheritedInterfaces + 1];
709     //determine the number of all interface methods, including the inherited
710     //interfaces
711     int numMethods = arThisMethods->get_Length();
712     for (int i= 0; i < m_nInheritedInterfaces; i++)
713     {
714         numMethods += arInheritedIfaces[i]->GetMethods()->get_Length();
715     }
716     //array containing MethodInfos of the cli object
717     m_arMethodInfos = new sr::MethodInfo*[numMethods];
718     //array containing MethodInfos of the interface
719     m_arInterfaceMethodInfos = new sr::MethodInfo*[numMethods];
720     //array containing the mapping of Uno interface pos to pos in
721     //m_arMethodInfos
722     m_arUnoPosToCliPos = new System::Int32[numMethods];
723     // initialize with -1
724     for (int i = 0; i < numMethods; i++)
725         m_arUnoPosToCliPos[i] = -1;
726 
727 #if OSL_DEBUG_LEVEL >= 2
728     sr::MethodInfo* arMethodInfosDbg[];
729     sr::MethodInfo* arInterfaceMethodInfosDbg[];
730     System::Int32 arInterfaceMethodCountDbg[];
731     arMethodInfosDbg = m_arMethodInfos;
732     arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos;
733     arInterfaceMethodCountDbg = m_arInterfaceMethodCount;
734 #endif
735 
736 
737     //fill m_arMethodInfos with the mappings
738     // !!! InterfaceMapping.TargetMethods should be MethodInfo*[] according
739     // to documentation
740     // but it is Type*[] instead. Bug in the framework?
741     System::Type* objType = m_cliI->GetType();
742     try
743     {
744         int index = 0;
745         // now get the methods from the inherited interface
746         //arInheritedIfaces[0] is the direct base interface
747         //arInheritedIfaces[n] is the furthest inherited interface
748         //Start with the base interface
749         int nArLength = arInheritedIfaces->get_Length();
750         for (;nArLength > 0; nArLength--)
751         {
752             sr::InterfaceMapping mapInherited = objType->GetInterfaceMap(
753                 arInheritedIfaces[nArLength - 1]);
754             int numMethods = mapInherited.TargetMethods->get_Length();
755             m_arInterfaceMethodCount[nArLength - 1] = numMethods;
756             for (int i = 0; i < numMethods; i++, index++)
757             {
758                 m_arMethodInfos[index] = __try_cast<sr::MethodInfo*>(
759                     mapInherited.TargetMethods[i]);
760 
761                 m_arInterfaceMethodInfos[index] = __try_cast<sr::MethodInfo*>(
762                     mapInherited.InterfaceMethods[i]);
763             }
764         }
765         //At last come the methods of the furthest derived interface
766         sr::InterfaceMapping map = objType->GetInterfaceMap(m_type);
767         nArLength = map.TargetMethods->get_Length();
768         m_arInterfaceMethodCount[m_nInheritedInterfaces] = nArLength;
769         for (int i = 0; i < nArLength; i++,index++)
770         {
771             m_arMethodInfos[index]= __try_cast<sr::MethodInfo*>(
772                 map.TargetMethods[i]);
773             m_arInterfaceMethodInfos[index]= __try_cast<sr::MethodInfo*>(
774                 map.InterfaceMethods[i]);
775         }
776     }
777     catch (System::InvalidCastException* )
778     {
779         OUStringBuffer buf( 128 );
780         buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
781                             "[cli_uno bridge] preparing proxy for "
782                             "cli interface: ") );
783         buf.append(mapCliString(m_type->ToString() ));
784         buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" \nfailed!"));
785         throw BridgeRuntimeError( buf.makeStringAndClear() );
786     }
787 }
788 
789 sr::MethodInfo* CliProxy::getMethodInfo(int nUnoFunctionPos,
790                                            const rtl::OUString& usMethodName, MethodKind methodKind)
791 {
792     sr::MethodInfo* ret = NULL;
793 #if OSL_DEBUG_LEVEL >= 2
794     System::String* sMethodNameDbg;
795     sr::MethodInfo* arMethodInfosDbg[];
796     sr::MethodInfo* arInterfaceMethodInfosDbg[];
797     System::Int32 arInterfaceMethodCountDbg[];
798     System::Int32 arUnoPosToCliPosDbg[];
799     sMethodNameDbg = mapUnoString(usMethodName.pData);
800     arMethodInfosDbg = m_arMethodInfos;
801     arInterfaceMethodInfosDbg = m_arInterfaceMethodInfos;
802     arInterfaceMethodCountDbg = m_arInterfaceMethodCount;
803     arUnoPosToCliPosDbg = m_arUnoPosToCliPos;
804 #endif
805     //deduct 3 for XInterface methods
806     nUnoFunctionPos -= 3;
807     System::Threading::Monitor::Enter(m_arUnoPosToCliPos);
808     try
809     {
810         int cliPos = m_arUnoPosToCliPos[nUnoFunctionPos];
811         if (cliPos != -1)
812             return m_arMethodInfos[cliPos];
813 
814         //create the method function name
815         System::String* sMethodName = mapUnoString(usMethodName.pData);
816         switch (methodKind)
817         {
818         case MK_METHOD:
819             break;
820         case MK_SET:
821             sMethodName = System::String::Concat(
822                 const_cast<System::String*>(Constants::sAttributeSet),
823                 sMethodName);
824             break;
825         case MK_GET:
826             sMethodName = System::String::Concat(
827                 const_cast<System::String*>(Constants::sAttributeGet),
828                 sMethodName);
829             break;
830         default:
831             OSL_ASSERT(0);
832         }
833         //Find the cli interface method that corresponds to the Uno method
834 //        System::String* sMethodName= mapUnoString(usMethodName.pData);
835         int indexCliMethod = -1;
836         //If the cli interfaces and their methods are in the same order
837         //as they were declared (inheritance chain and within the interface)
838         //then nUnoFunctionPos should lead to the correct method. However,
839         //the documentation does not say that this ordering is given.
840         if (sMethodName->Equals(m_arInterfaceMethodInfos[nUnoFunctionPos]->Name))
841             indexCliMethod = nUnoFunctionPos;
842         else
843         {
844             int cMethods = m_arInterfaceMethodInfos->get_Length();
845             for (int i = 0; i < cMethods; i++)
846             {
847                 System::String* cliMethod = m_arInterfaceMethodInfos[i]->Name;
848                 if (cliMethod->Equals(sMethodName))
849                 {
850                     indexCliMethod = i;
851                     break;
852                 }
853             }
854         }
855         if (indexCliMethod == -1)
856         {
857             OUStringBuffer buf(256);
858             buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(
859                                 "[cli_uno bridge] CliProxy::getMethodInfo():"
860                                 "cli object does not implement interface method: "));
861             buf.append(usMethodName);
862             throw BridgeRuntimeError(buf.makeStringAndClear());
863             return 0;
864         }
865         m_arUnoPosToCliPos[nUnoFunctionPos] = indexCliMethod;
866         ret = m_arMethodInfos[indexCliMethod];
867     }
868     __finally
869     {
870         System::Threading::Monitor::Exit(m_arUnoPosToCliPos);
871     }
872 
873     return ret;
874 }
875 
876 CliProxy::~CliProxy()
877 {
878 #if OSL_DEBUG_LEVEL >= 2
879     sd::Trace::WriteLine(System::String::Format(
880                   new System::String(
881                   S"cli uno bridge: Destroying proxy for cli object, "
882                   S"id:\n\t{0}\n\t{1}\n"),
883                   m_oid, m_type));
884 #endif
885 	CliEnvHolder::g_cli_env->revokeInterface(m_oid, mapUnoType(m_unoType.get()));
886     m_bridge->release();
887 }
888 
889 uno_Interface* CliProxy::create(Bridge const * bridge,
890                                  System::Object* cliI,
891                                  typelib_TypeDescription const* pTD,
892                                  const rtl::OUString& ousOid)
893 {
894     uno_Interface* proxy= static_cast<uno_Interface*>(
895         new CliProxy(bridge, cliI, pTD, ousOid));
896 
897     //register proxy with target environment (uno)
898     (*bridge->m_uno_env->registerProxyInterface)(
899        bridge->m_uno_env,
900        reinterpret_cast<void**>(&proxy),
901        cli_proxy_free,
902        ousOid.pData, (typelib_InterfaceTypeDescription*) pTD);
903     //register original interface
904 	CliEnvHolder::g_cli_env->registerInterface(cliI, mapUnoString(ousOid.pData),
905                        mapUnoType((pTD)));
906 
907     return proxy;
908 }
909 
910 
911 
912 void SAL_CALL CliProxy::uno_DispatchMethod(
913         struct _uno_Interface *,
914         const struct _typelib_TypeDescription *,
915         void *,
916         void **,
917         uno_Any ** )
918 {
919 }
920 inline void CliProxy::acquire() const
921 {
922     if (1 == osl_incrementInterlockedCount( &m_ref ))
923     {
924         // rebirth of proxy zombie
925         void * that = const_cast< CliProxy * >( this );
926         // register at uno env
927         (*m_bridge->m_uno_env->registerProxyInterface)(
928             m_bridge->m_uno_env, &that,
929             cli_proxy_free, m_usOid.pData,
930             (typelib_InterfaceTypeDescription *)m_unoType.get() );
931 #if OSL_DEBUG_LEVEL >= 2
932         OSL_ASSERT( this == (void const * const)that );
933 #endif
934     }
935 }
936 //---------------------------------------------------------------------------
937 inline void CliProxy::release() const
938 {
939     if (0 == osl_decrementInterlockedCount( &m_ref ))
940     {
941         // revoke from uno env on last release,
942         // The proxy can be resurrected if acquire is called before the uno
943         // environment calls cli_proxy_free. cli_proxy_free will
944         //delete the proxy. The environment does not acquire a registered
945         //proxy.
946         (*m_bridge->m_uno_env->revokeInterface)(
947             m_bridge->m_uno_env, const_cast< CliProxy * >( this ) );
948     }
949 }
950 }
951 
952 
953 
954 
955 extern "C"
956 void SAL_CALL cli_proxy_free( uno_ExtEnvironment *, void * proxy )
957     SAL_THROW_EXTERN_C()
958 {
959     cli_uno::CliProxy * cliProxy = reinterpret_cast<
960         cli_uno::CliProxy * >( proxy );
961 
962     delete cliProxy;
963 }
964 
965 extern "C"
966 void SAL_CALL cli_proxy_acquire( uno_Interface * pUnoI )
967     SAL_THROW_EXTERN_C()
968 {
969     CliProxy const * cliProxy = static_cast< CliProxy const * >( pUnoI );
970     cliProxy->acquire();
971 }
972 //-----------------------------------------------------------------------------
973 extern "C"
974 void SAL_CALL cli_proxy_release( uno_Interface * pUnoI )
975     SAL_THROW_EXTERN_C()
976 {
977     CliProxy * cliProxy = static_cast< CliProxy * >( pUnoI );
978     cliProxy->release();
979 }
980 
981 //------------------------------------------------------------------------------
982 extern "C"
983 
984 void SAL_CALL cli_proxy_dispatch(
985     uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
986     void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
987     SAL_THROW_EXTERN_C()
988 {
989     CliProxy * proxy = static_cast< CliProxy* >( pUnoI );
990     try
991     {
992         Bridge const* bridge = proxy->m_bridge;
993 
994         switch (member_td->eTypeClass)
995         {
996         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
997         {
998 
999             sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
1000                                     member_td)->nPosition;
1001             typelib_InterfaceTypeDescription * iface_td =
1002                 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
1003             OSL_ENSURE(
1004                 member_pos < iface_td->nAllMembers,
1005                 "### member pos out of range!" );
1006             sal_Int32 function_pos =
1007                 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
1008             OSL_ENSURE(
1009                 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
1010                 "### illegal function index!" );
1011 
1012             if (uno_ret) // is getter method
1013             {
1014                OUString const& usAttrName= *(rtl_uString**)&
1015                    ((typelib_InterfaceMemberTypeDescription*) member_td)
1016                    ->pMemberName;
1017                sr::MethodInfo* info = proxy->getMethodInfo(function_pos,
1018                                              usAttrName, CliProxy::MK_GET);
1019                bridge->call_cli(
1020                     proxy->m_cliI,
1021                     info,
1022                     ((typelib_InterfaceAttributeTypeDescription *)member_td)
1023                     ->pAttributeTypeRef,
1024                     0, 0, // no params
1025                     uno_ret, 0, uno_exc );
1026             }
1027             else // is setter method
1028             {
1029                 OUString const& usAttrName= *(rtl_uString**) &
1030                     ((typelib_InterfaceMemberTypeDescription*) member_td)
1031                     ->pMemberName;
1032                 sr::MethodInfo* info = proxy->getMethodInfo(function_pos + 1,
1033                                               usAttrName, CliProxy::MK_SET);
1034                 typelib_MethodParameter param;
1035                 param.pTypeRef =
1036                     ((typelib_InterfaceAttributeTypeDescription *)member_td)
1037                     ->pAttributeTypeRef;
1038                 param.bIn = sal_True;
1039                 param.bOut = sal_False;
1040 
1041                 bridge->call_cli(
1042                     proxy->m_cliI,
1043                     // set follows get method
1044                     info,
1045                     0 /* indicates void return */, &param, 1,
1046                     0, uno_args, uno_exc );
1047            }
1048             break;
1049         }
1050         case typelib_TypeClass_INTERFACE_METHOD:
1051         {
1052             sal_Int32 member_pos = ((typelib_InterfaceMemberTypeDescription *)
1053                                     member_td)->nPosition;
1054             typelib_InterfaceTypeDescription * iface_td =
1055                 (typelib_InterfaceTypeDescription *)proxy->m_unoType.get();
1056             OSL_ENSURE(
1057                 member_pos < iface_td->nAllMembers,
1058                 "### member pos out of range!" );
1059             sal_Int32 function_pos =
1060                 iface_td->pMapMemberIndexToFunctionIndex[ member_pos ];
1061             OSL_ENSURE(
1062                 function_pos < iface_td->nMapFunctionIndexToMemberIndex,
1063                 "### illegal function index!" );
1064 
1065             switch (function_pos)
1066             {
1067             case 0: // queryInterface()
1068             {
1069                 TypeDescr demanded_td(
1070                     *reinterpret_cast<typelib_TypeDescriptionReference **>(
1071                         uno_args[0]));
1072                 if (typelib_TypeClass_INTERFACE
1073                     != demanded_td.get()->eTypeClass)
1074                 {
1075                     throw BridgeRuntimeError(
1076                     OUSTR("queryInterface() call demands an INTERFACE type!"));
1077                 }
1078 
1079                 uno_Interface * pInterface = 0;
1080                 (*bridge->m_uno_env->getRegisteredInterface)(
1081                     bridge->m_uno_env,
1082                     (void **)&pInterface, proxy->m_usOid.pData,
1083                     (typelib_InterfaceTypeDescription *)demanded_td.get() );
1084 
1085                 if (0 == pInterface)
1086                 {
1087                     System::Type* mgdDemandedType =
1088                         mapUnoType(demanded_td.get());
1089                     if (mgdDemandedType->IsInstanceOfType( proxy->m_cliI ))
1090                     {
1091 #if OSL_DEBUG_LEVEL > 0
1092                         OUString usOid(
1093                             mapCliString(
1094 							CliEnvHolder::g_cli_env->getObjectIdentifier(
1095                                     proxy->m_cliI )));
1096                         OSL_ENSURE(usOid.equals( proxy->m_usOid ),
1097                                     "### different oids!");
1098 #endif
1099                         uno_Interface* pUnoI = bridge->map_cli2uno(
1100                             proxy->m_cliI, demanded_td.get() );
1101                         uno_any_construct(
1102                             (uno_Any *)uno_ret, &pUnoI, demanded_td.get(), 0 );
1103                         (*pUnoI->release)( pUnoI );
1104                     }
1105                     else // object does not support demanded interface
1106                     {
1107                         uno_any_construct( (uno_Any *)uno_ret, 0, 0, 0 );
1108                     }
1109                     // no excetpion occured
1110                     *uno_exc = 0;
1111                 }
1112                 else
1113                 {
1114                     uno_any_construct(
1115                         reinterpret_cast< uno_Any * >( uno_ret ),
1116                         &pInterface, demanded_td.get(), 0 );
1117                     (*pInterface->release)( pInterface );
1118                     *uno_exc = 0;
1119                 }
1120                 break;
1121             }
1122             case 1: // acquire this proxy
1123                 cli_proxy_acquire(proxy);
1124                 *uno_exc = 0;
1125                 break;
1126             case 2: // release this proxy
1127                 cli_proxy_release(proxy);
1128                 *uno_exc = 0;
1129                 break;
1130             default: // arbitrary method call
1131             {
1132                 typelib_InterfaceMethodTypeDescription * method_td =
1133                     (typelib_InterfaceMethodTypeDescription *)member_td;
1134                OUString const& usMethodName= *(rtl_uString**) &
1135                    ((typelib_InterfaceMemberTypeDescription*) member_td)
1136                    ->pMemberName;
1137 
1138                sr::MethodInfo* info = proxy->getMethodInfo(function_pos,
1139                                              usMethodName, CliProxy::MK_METHOD);
1140                bridge->call_cli(
1141                     proxy->m_cliI,
1142                     info,
1143                     method_td->pReturnTypeRef, method_td->pParams,
1144                     method_td->nParams,
1145                     uno_ret, uno_args, uno_exc);
1146                 return;
1147             }
1148             }
1149             break;
1150         }
1151         default:
1152         {
1153             throw BridgeRuntimeError(
1154                 OUSTR("illegal member type description!") );
1155         }
1156         }
1157     }
1158     catch (BridgeRuntimeError & err)
1159     {
1160         // binary identical struct
1161         ::com::sun::star::uno::RuntimeException exc(
1162             OUSTR("[cli_uno bridge error] ") + err.m_message,
1163             ::com::sun::star::uno::Reference<
1164             ::com::sun::star::uno::XInterface >() );
1165         ::com::sun::star::uno::Type const & exc_type = ::getCppuType( & exc);
1166         uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0);
1167 #if OSL_DEBUG_LEVEL >= 1
1168         OString cstr_msg(OUStringToOString(exc.Message,
1169                                              RTL_TEXTENCODING_ASCII_US ) );
1170         OSL_ENSURE(0, cstr_msg.getStr());
1171 #endif
1172     }
1173 }
1174 
1175 
1176 
1177 
1178 
1179