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