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