merge the formfield patch from ooo-build
[ooovba.git] / bridges / source / cpp_uno / gcc3_linux_arm / uno2cpp.cxx
blob451ae7c596f29beb456f80b0e3b3886d660e304e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: uno2cpp.cxx,v $
10 * $Revision: 1.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <malloc.h>
32 #include <rtl/alloc.h>
34 #include <com/sun/star/uno/genfunc.hxx>
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include <uno/data.h>
38 #include <bridges/cpp_uno/shared/bridge.hxx>
39 #include <bridges/cpp_uno/shared/types.hxx>
40 #include <bridges/cpp_uno/shared/unointerfaceproxy.hxx>
41 #include <bridges/cpp_uno/shared/vtables.hxx>
43 #include "share.hxx"
45 #include <stdio.h>
46 #include <string.h>
48 /*
49 * Based on http://gcc.gnu.org/PR41443
50 * References to __SOFTFP__ are incorrect for EABI; the __SOFTFP__ code
51 * should be used for *soft-float ABI* whether or not VFP is enabled,
52 * and __SOFTFP__ does specifically mean soft-float not soft-float ABI.
54 * Changing the conditionals to __SOFTFP__ || __ARM_EABI__ then
55 * -mfloat-abi=softfp should work. -mfloat-abi=hard won't; that would
56 * need both a new macro to identify the hard-VFP ABI.
58 #if !defined(__ARM_EABI__) && !defined(__SOFTFP__)
59 #error Not Implemented
62 some possibly handy code to detect that we have VFP registers
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <fcntl.h>
68 #include <unistd.h>
69 #include <elf.h>
71 #define HWCAP_ARM_VFP 64
73 int hasVFP(void)
75 int fd = open ("/proc/self/auxv", O_RDONLY);
76 if (fd == -1)
77 return -1;
79 int ret = -1;
81 Elf32_auxv_t buf[128];
82 ssize_t n;
83 while ((ret == -1) && ((n = read(fd, buf, sizeof (buf))) > 0))
85 for (int i = 0; i < 128; ++i)
87 if (buf[i].a_type == AT_HWCAP)
89 ret = (buf[i].a_un.a_val & HWCAP_ARM_VFP) ? true : false;
90 break;
92 else if (buf[i].a_type == AT_NULL)
94 ret = -2;
95 break;
100 close (fd);
101 return ret;
104 #endif
106 using namespace ::rtl;
107 using namespace ::com::sun::star::uno;
109 namespace arm
111 enum armlimits { MAX_GPR_REGS = 4 };
114 void MapReturn(long r0, long r1, typelib_TypeClass eReturnType, void *pRegisterReturn)
116 #if !defined(__ARM_EABI__) && !defined(__SOFTFP__)
117 register float fret asm("f0");
118 register double dret asm("f0");
119 #endif
121 switch( eReturnType )
123 case typelib_TypeClass_HYPER:
124 case typelib_TypeClass_UNSIGNED_HYPER:
125 ((long*)pRegisterReturn)[1] = r1;
126 case typelib_TypeClass_LONG:
127 case typelib_TypeClass_UNSIGNED_LONG:
128 case typelib_TypeClass_ENUM:
129 ((long*)pRegisterReturn)[0] = r0;
130 break;
131 case typelib_TypeClass_CHAR:
132 case typelib_TypeClass_SHORT:
133 case typelib_TypeClass_UNSIGNED_SHORT:
134 *(unsigned short*)pRegisterReturn = (unsigned short)r0;
135 break;
136 case typelib_TypeClass_BOOLEAN:
137 case typelib_TypeClass_BYTE:
138 *(unsigned char*)pRegisterReturn = (unsigned char)r0;
139 break;
140 case typelib_TypeClass_FLOAT:
141 #if defined(__ARM_EABI__) || defined(__SOFTFP__)
142 ((long*)pRegisterReturn)[0] = r0;
143 #else
144 *(float*)pRegisterReturn = fret;
145 #endif
146 break;
147 case typelib_TypeClass_DOUBLE:
148 #if defined(__ARM_EABI__) || defined(__SOFTFP__)
149 ((long*)pRegisterReturn)[1] = r1;
150 ((long*)pRegisterReturn)[0] = r0;
151 #else
152 *(double*)pRegisterReturn = dret;
153 #endif
154 break;
155 default:
156 break;
160 namespace
162 //================================================================
164 void callVirtualMethod(
165 void * pThis,
166 sal_Int32 nVtableIndex,
167 void * pRegisterReturn,
168 typelib_TypeClass eReturnType,
169 sal_uInt32 *pStack,
170 sal_uInt32 nStack,
171 sal_uInt32 *pGPR,
172 sal_uInt32 nGPR) __attribute__((noinline));
174 void callVirtualMethod(
175 void * pThis,
176 sal_Int32 nVtableIndex,
177 void * pRegisterReturn,
178 typelib_TypeClass eReturnType,
179 sal_uInt32 *pStack,
180 sal_uInt32 nStack,
181 sal_uInt32 *pGPR,
182 sal_uInt32 nGPR)
184 // never called
185 if (! pThis)
186 CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
188 if ( nStack )
190 // 8-bytes aligned
191 sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 8;
192 sal_uInt32 *stack = (sal_uInt32 *) __builtin_alloca( nStackBytes );
193 memcpy( stack, pStack, nStackBytes );
196 // Should not happen, but...
197 if ( nGPR > arm::MAX_GPR_REGS )
198 nGPR = arm::MAX_GPR_REGS;
200 sal_uInt32 pMethod = *((sal_uInt32*)pThis);
201 pMethod += 4 * nVtableIndex;
202 pMethod = *((sal_uInt32 *)pMethod);
204 typedef void (*FunctionCall )( sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32);
205 FunctionCall pFunc = (FunctionCall)pMethod;
207 // fill registers
208 __asm__ __volatile__ (
209 "ldr r0, [%0, #0]\n\t"
210 "ldr r1, [%0, #4]\n\t"
211 "ldr r2, [%0, #8]\n\t"
212 "ldr r3, [%0, #12]\n\t"
213 : : "r" (pGPR)
214 : "r0", "r1", "r2", "r3"
217 // tell gcc that r0 to r3 are not available to it
218 register sal_uInt32 r0 asm("r0");
219 register sal_uInt32 r1 asm("r1");
220 register sal_uInt32 r2 asm("r2");
221 register sal_uInt32 r3 asm("r3");
223 (*pFunc)(r0, r1, r2, r3);
225 // get return value
226 __asm__ __volatile__ (
227 "mov %0, r0\n\t"
228 "mov %1, r1\n\t"
229 : "=r" (r0), "=r" (r1) : );
231 MapReturn(r0, r1, eReturnType, pRegisterReturn);
235 #define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow ) \
236 if ( nr < arm::MAX_GPR_REGS ) \
237 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
238 else \
239 bOverFlow = true; \
240 if (bOverFlow) \
241 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
243 #ifdef __ARM_EABI__
244 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow ) \
245 if ( (nr < arm::MAX_GPR_REGS) && (nr % 2) ) \
247 ++nr; \
249 if ( nr < arm::MAX_GPR_REGS ) \
251 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
252 pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
254 else \
255 bOverFlow = true; \
256 if (bOverFlow) \
258 if ( (pDS - pStart) % 2) \
260 ++pDS; \
262 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
263 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
265 #else
266 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow ) \
267 INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow) \
268 INSERT_INT32( ((sal_uInt32*)pSV)+1, nr, pGPR, pDS, bOverflow)
269 #endif
271 #define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverflow ) \
272 INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow)
274 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverflow ) \
275 INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow )
277 #define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \
278 if ( nr < arm::MAX_GPR_REGS ) \
279 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
280 else \
281 bOverFlow = true; \
282 if (bOverFlow) \
283 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
285 #define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \
286 if ( nr < arm::MAX_GPR_REGS ) \
287 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
288 else \
289 bOverFlow = true; \
290 if (bOverFlow) \
291 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
293 namespace {
294 //=======================================================================
295 static void cpp_call(
296 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
297 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
298 typelib_TypeDescriptionReference * pReturnTypeRef,
299 sal_Int32 nParams, typelib_MethodParameter * pParams,
300 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
302 // max space for: [complex ret ptr], values|ptr ...
303 sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
304 sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
305 sal_uInt32 * pStackStart = pStack;
307 sal_uInt32 pGPR[arm::MAX_GPR_REGS];
308 sal_uInt32 nGPR = 0;
310 // return
311 typelib_TypeDescription * pReturnTypeDescr = 0;
312 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
313 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
315 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
317 bool bOverFlow = false;
319 if (pReturnTypeDescr)
322 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
324 pCppReturn = pUnoReturn; // direct way for simple types
326 else
328 // complex return via ptr
329 pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
330 ? __builtin_alloca( pReturnTypeDescr->nSize )
331 : pUnoReturn); // direct way
333 INSERT_INT32( &pCppReturn, nGPR, pGPR, pStack, bOverFlow );
336 // push this
337 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
338 + aVtableSlot.offset;
339 INSERT_INT32( &pAdjustedThisPtr, nGPR, pGPR, pStack, bOverFlow );
341 // stack space
342 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
343 // args
344 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
345 // indizes of values this have to be converted (interface conversion cpp<=>uno)
346 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
347 // type descriptions for reconversions
348 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
350 sal_Int32 nTempIndizes = 0;
352 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
354 const typelib_MethodParameter & rParam = pParams[nPos];
355 typelib_TypeDescription * pParamTypeDescr = 0;
356 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
358 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
360 // uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos],
361 uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
362 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
364 switch (pParamTypeDescr->eTypeClass)
366 case typelib_TypeClass_HYPER:
367 case typelib_TypeClass_UNSIGNED_HYPER:
368 #ifdef CMC_DEBUG
369 fprintf(stderr, "hyper is %lx\n", pCppArgs[nPos]);
370 #endif
371 INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart, bOverFlow );
372 break;
373 case typelib_TypeClass_LONG:
374 case typelib_TypeClass_UNSIGNED_LONG:
375 case typelib_TypeClass_ENUM:
376 #ifdef CMC_DEBUG
377 fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
378 #endif
379 INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow );
380 break;
381 case typelib_TypeClass_SHORT:
382 case typelib_TypeClass_CHAR:
383 case typelib_TypeClass_UNSIGNED_SHORT:
384 INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow );
385 break;
386 case typelib_TypeClass_BOOLEAN:
387 case typelib_TypeClass_BYTE:
388 INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow );
389 break;
390 case typelib_TypeClass_FLOAT:
391 INSERT_FLOAT( pCppArgs[nPos], nGPR, pGPR, pStack, bOverFlow );
392 break;
393 case typelib_TypeClass_DOUBLE:
394 INSERT_DOUBLE( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart, bOverFlow );
395 break;
397 // no longer needed
398 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
400 else // ptr to complex value | ref
402 if (! rParam.bIn) // is pure out
404 // cpp out is constructed mem, uno out is not!
405 uno_constructData(
406 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
407 pParamTypeDescr );
408 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
409 // will be released at reconversion
410 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
412 // is in/inout
413 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
415 uno_copyAndConvertData(
416 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
417 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
419 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
420 // will be released at reconversion
421 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
423 else // direct way
425 pCppArgs[nPos] = pUnoArgs[nPos];
426 // no longer needed
427 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
429 INSERT_INT32( &(pCppArgs[nPos]), nGPR, pGPR, pStack, bOverFlow );
435 callVirtualMethod(
436 pAdjustedThisPtr, aVtableSlot.index,
437 pCppReturn, pReturnTypeDescr->eTypeClass,
438 pStackStart,
439 (pStack - pStackStart),
440 pGPR, nGPR);
442 // NO exception occured...
443 *ppUnoExc = 0;
445 // reconvert temporary params
446 for ( ; nTempIndizes--; )
448 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
449 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
451 if (pParams[nIndex].bIn)
453 if (pParams[nIndex].bOut) // inout
455 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
456 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
457 pThis->getBridge()->getCpp2Uno() );
460 else // pure out
462 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
463 pThis->getBridge()->getCpp2Uno() );
465 // destroy temp cpp param => cpp: every param was constructed
466 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
468 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
470 // return value
471 if (pCppReturn && pUnoReturn != pCppReturn)
473 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
474 pThis->getBridge()->getCpp2Uno() );
475 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
478 catch (...)
480 // __asm__ __volatile__ ("sub sp, sp, #2048\n");
482 // fill uno exception
483 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
485 // temporary params
486 for ( ; nTempIndizes--; )
488 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
489 // destroy temp cpp param => cpp: every param was constructed
490 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
491 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
494 // return type
495 if (pReturnTypeDescr)
496 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
501 namespace bridges { namespace cpp_uno { namespace shared {
503 void unoInterfaceProxyDispatch(
504 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
505 void * pReturn, void * pArgs[], uno_Any ** ppException )
507 // is my surrogate
508 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
509 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
510 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
512 switch (pMemberDescr->eTypeClass)
514 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
516 // determine vtable call index
517 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
518 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
520 VtableSlot aVtableSlot(
521 getVtableSlot(
522 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
523 (pMemberDescr)));
525 if (pReturn)
527 // dependent dispatch
528 cpp_call(
529 pThis, aVtableSlot,
530 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
531 0, 0, // no params
532 pReturn, pArgs, ppException );
534 else
536 // is SET
537 typelib_MethodParameter aParam;
538 aParam.pTypeRef =
539 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
540 aParam.bIn = sal_True;
541 aParam.bOut = sal_False;
543 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
544 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
545 typelib_typedescriptionreference_new(
546 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
548 // dependent dispatch
549 aVtableSlot.index += 1;
550 cpp_call(
551 pThis, aVtableSlot, // get, then set method
552 pReturnTypeRef,
553 1, &aParam,
554 pReturn, pArgs, ppException );
556 typelib_typedescriptionreference_release( pReturnTypeRef );
559 break;
561 case typelib_TypeClass_INTERFACE_METHOD:
563 // determine vtable call index
564 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
565 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
567 VtableSlot aVtableSlot(
568 getVtableSlot(
569 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
570 (pMemberDescr)));
572 switch (aVtableSlot.index)
574 // standard calls
575 case 1: // acquire uno interface
576 (*pUnoI->acquire)( pUnoI );
577 *ppException = 0;
578 break;
579 case 2: // release uno interface
580 (*pUnoI->release)( pUnoI );
581 *ppException = 0;
582 break;
583 case 0: // queryInterface() opt
585 typelib_TypeDescription * pTD = 0;
586 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
587 if (pTD)
589 uno_Interface * pInterface = 0;
590 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
591 pThis->getBridge()->getUnoEnv(),
592 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
594 if (pInterface)
596 ::uno_any_construct(
597 reinterpret_cast< uno_Any * >( pReturn ),
598 &pInterface, pTD, 0 );
599 (*pInterface->release)( pInterface );
600 TYPELIB_DANGER_RELEASE( pTD );
601 *ppException = 0;
602 break;
604 TYPELIB_DANGER_RELEASE( pTD );
606 } // else perform queryInterface()
607 default:
608 // dependent dispatch
609 cpp_call(
610 pThis, aVtableSlot,
611 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
612 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
613 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
614 pReturn, pArgs, ppException );
616 break;
618 default:
620 ::com::sun::star::uno::RuntimeException aExc(
621 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
622 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
624 Type const & rExcType = ::getCppuType( &aExc );
625 // binary identical null reference
626 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
631 } } }
633 /* vi:set tabstop=4 shiftwidth=4 expandtab: */