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
UnoInterfaceInfo(Bridge const * bridge,uno_Interface * unoI,typelib_InterfaceTypeDescription * td)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 }
~UnoInterfaceInfo()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
UnoInterfaceProxy(Bridge * bridge,uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTD,const OUString & oid)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
~UnoInterfaceProxy()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
create(Bridge * bridge,uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTD,const OUString & oid)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
addUnoInterface(uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTd)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
CanCastTo(System::Type * fromType,System::Object *)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
invokeObject(sc::IDictionary * props,srrm::LogicalCallContext * context,srrm::IMethodCallMessage * mcm)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
findInfo(::System::Type * type)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
Invoke(srrm::IMessage * callmsg)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, ¶m, 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 */
constructReturnMessage(System::Object * cliReturn,System::Object * args[],typelib_InterfaceMethodTypeDescription * mtd,srrm::IMessage * msg,System::Object * exc)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 //################################################################################
CliProxy(Bridge const * bridge,System::Object * cliI,typelib_TypeDescription const * td,const rtl::OUString & usOid)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
makeMethodInfos()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
getMethodInfo(int nUnoFunctionPos,const rtl::OUString & usMethodName,MethodKind methodKind)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
~CliProxy()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
create(Bridge const * bridge,System::Object * cliI,typelib_TypeDescription const * pTD,const rtl::OUString & ousOid)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
uno_DispatchMethod(struct _uno_Interface *,const struct _typelib_TypeDescription *,void *,void **,uno_Any **)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 }
acquire() const916 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 //---------------------------------------------------------------------------
release() const933 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"
cli_proxy_free(uno_ExtEnvironment *,void * proxy)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"
cli_proxy_acquire(uno_Interface * pUnoI)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"
cli_proxy_release(uno_Interface * pUnoI)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
cli_proxy_dispatch(uno_Interface * pUnoI,typelib_TypeDescription const * member_td,void * uno_ret,void * uno_args[],uno_Any ** uno_exc)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 */, ¶m, 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 occurred
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