1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 #pragma warning( disable : 4237 )
32 #include <hash_map>
33 #include <sal/config.h>
34 #include <malloc.h>
35 #include <new.h>
36 #include <typeinfo.h>
37 #include <signal.h>
38 
39 #include "rtl/alloc.h"
40 #include "rtl/strbuf.hxx"
41 #include "rtl/ustrbuf.hxx"
42 
43 #include "com/sun/star/uno/Any.hxx"
44 
45 #include "msci.hxx"
46 
47 
48 #pragma pack(push, 8)
49 
50 using namespace ::com::sun::star::uno;
51 using namespace ::std;
52 using namespace ::osl;
53 using namespace ::rtl;
54 
55 namespace CPPU_CURRENT_NAMESPACE
56 {
57 
58 //==================================================================================================
59 static inline OUString toUNOname( OUString const & rRTTIname ) throw ()
60 {
61 	OUStringBuffer aRet( 64 );
62 	OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
63     sal_Int32 nPos = aStr.getLength();
64     while (nPos > 0)
65     {
66         sal_Int32 n = aStr.lastIndexOf( '@', nPos );
67         aRet.append( aStr.copy( n +1, nPos -n -1 ) );
68         if (n >= 0)
69         {
70 			aRet.append( (sal_Unicode)'.' );
71         }
72         nPos = n;
73     }
74 	return aRet.makeStringAndClear();
75 }
76 //==================================================================================================
77 static inline OUString toRTTIname( OUString const & rUNOname ) throw ()
78 {
79 	OUStringBuffer aRet( 64 );
80 	aRet.appendAscii( RTL_CONSTASCII_STRINGPARAM(".?AV") ); // class ".?AV"; struct ".?AU"
81     sal_Int32 nPos = rUNOname.getLength();
82     while (nPos > 0)
83     {
84         sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
85         aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
86         aRet.append( (sal_Unicode)'@' );
87         nPos = n;
88     }
89 	aRet.append( (sal_Unicode)'@' );
90 	return aRet.makeStringAndClear();
91 }
92 
93 
94 //##################################################################################################
95 //#### RTTI simulation #############################################################################
96 //##################################################################################################
97 
98 
99 typedef hash_map< OUString, void *, OUStringHash, equal_to< OUString > > t_string2PtrMap;
100 
101 //==================================================================================================
102 class RTTInfos
103 {
104 	Mutex				_aMutex;
105 	t_string2PtrMap		_allRTTI;
106 
107 	static OUString toRawName( OUString const & rUNOname ) throw ();
108 public:
109 	type_info * getRTTI( OUString const & rUNOname ) throw ();
110 
111 	RTTInfos();
112 	~RTTInfos();
113 };
114 
115 //==================================================================================================
116 class __type_info
117 {
118 	friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
119 	friend int msci_filterCppException(
120         LPEXCEPTION_POINTERS, uno_Any *, uno_Mapping * );
121 
122 public:
123     virtual ~__type_info() throw ();
124 
125 	inline __type_info( void * m_data, const char * m_d_name ) throw ()
126 		: _m_data( m_data )
127         { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
128 
129 private:
130     void * _m_data;
131     char _m_d_name[1];
132 };
133 //__________________________________________________________________________________________________
134 __type_info::~__type_info() throw ()
135 {
136 }
137 //__________________________________________________________________________________________________
138 type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
139 {
140 	// a must be
141 	OSL_ENSURE( sizeof(__type_info) == sizeof(type_info), "### type info structure size differ!" );
142 
143 	MutexGuard aGuard( _aMutex );
144 	t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) );
145 
146 	// check if type is already available
147 	if (iFind == _allRTTI.end())
148 	{
149 		// insert new type_info
150 		OString aRawName( OUStringToOString( toRTTIname( rUNOname ), RTL_TEXTENCODING_ASCII_US ) );
151 		__type_info * pRTTI = new( ::rtl_allocateMemory( sizeof(__type_info) + aRawName.getLength() ) )
152             __type_info( NULL, aRawName.getStr() );
153 
154 		// put into map
155 		pair< t_string2PtrMap::iterator, bool > insertion(
156             _allRTTI.insert( t_string2PtrMap::value_type( rUNOname, pRTTI ) ) );
157         OSL_ENSURE( insertion.second, "### rtti insertion failed?!" );
158 
159 		return (type_info *)pRTTI;
160 	}
161 	else
162 	{
163 		return (type_info *)iFind->second;
164 	}
165 }
166 //__________________________________________________________________________________________________
167 RTTInfos::RTTInfos() throw ()
168 {
169 }
170 //__________________________________________________________________________________________________
171 RTTInfos::~RTTInfos() throw ()
172 {
173 #if OSL_DEBUG_LEVEL > 1
174 	OSL_TRACE( "> freeing generated RTTI infos... <\n" );
175 #endif
176 
177 	MutexGuard aGuard( _aMutex );
178 	for ( t_string2PtrMap::const_iterator iPos( _allRTTI.begin() );
179           iPos != _allRTTI.end(); ++iPos )
180 	{
181 		__type_info * pType = (__type_info *)iPos->second;
182 		pType->~__type_info(); // obsolete, but good style...
183 		::rtl_freeMemory( pType );
184 	}
185 }
186 
187 
188 //##################################################################################################
189 //#### Exception raising ###########################################################################
190 //##################################################################################################
191 
192 
193 //==================================================================================================
194 struct ObjectFunction
195 {
196 	char somecode[12];
197 	typelib_TypeDescription * _pTypeDescr; // type of object
198 
199     inline static void * operator new ( size_t nSize );
200     inline static void operator delete ( void * pMem );
201 
202 	ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ();
203 	~ObjectFunction() throw ();
204 };
205 
206 inline void * ObjectFunction::operator new ( size_t nSize )
207 {
208     void * pMem = rtl_allocateMemory( nSize );
209     if (pMem != 0)
210     {
211         DWORD old_protect;
212 #if OSL_DEBUG_LEVEL > 0
213         BOOL success =
214 #endif
215         VirtualProtect( pMem, nSize, PAGE_EXECUTE_READWRITE, &old_protect );
216         OSL_ENSURE( success, "VirtualProtect() failed!" );
217     }
218     return pMem;
219 }
220 
221 inline void ObjectFunction::operator delete ( void * pMem )
222 {
223     rtl_freeMemory( pMem );
224 }
225 
226 //__________________________________________________________________________________________________
227 ObjectFunction::ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ()
228 	: _pTypeDescr( pTypeDescr )
229 {
230 	::typelib_typedescription_acquire( _pTypeDescr );
231 
232 	unsigned char * pCode = (unsigned char *)somecode;
233 	// a must be!
234 	OSL_ENSURE( (void *)this == (void *)pCode, "### unexpected!" );
235 
236 	// push ObjectFunction this
237 	*pCode++ = 0x68;
238 	*(void **)pCode = this;
239 	pCode += sizeof(void *);
240 	// jmp rel32 fpFunc
241 	*pCode++ = 0xe9;
242 	*(sal_Int32 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int32);
243 }
244 //__________________________________________________________________________________________________
245 ObjectFunction::~ObjectFunction() throw ()
246 {
247 	::typelib_typedescription_release( _pTypeDescr );
248 }
249 
250 //==================================================================================================
251 static void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis )
252 	throw ()
253 {
254 	::uno_copyData( pExcThis, pSource, pThis->_pTypeDescr, cpp_acquire );
255 	return pExcThis;
256 }
257 //==================================================================================================
258 static void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis )
259 	throw ()
260 {
261 	::uno_destructData( pExcThis, pThis->_pTypeDescr, cpp_release );
262 	return pExcThis;
263 }
264 
265 // these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr
266 
267 //==================================================================================================
268 static __declspec(naked) void copyConstruct() throw ()
269 {
270 	__asm
271 	{
272 		// ObjectFunction this already on stack
273 		push [esp+8]  // source exc object this
274 		push ecx	  // exc object
275 		call __copyConstruct
276 		add  esp, 12  // + ObjectFunction this
277 		ret  4
278 	}
279 }
280 //==================================================================================================
281 static __declspec(naked) void destruct() throw ()
282 {
283 	__asm
284 	{
285 		// ObjectFunction this already on stack
286 		push ecx	// exc object
287 		call __destruct
288 		add  esp, 8 // + ObjectFunction this
289 		ret
290 	}
291 }
292 
293 //==================================================================================================
294 struct ExceptionType
295 {
296 	sal_Int32			_n0;
297 	type_info *			_pTypeInfo;
298 	sal_Int32			_n1, _n2, _n3, _n4;
299 	ObjectFunction *	_pCopyCtor;
300 	sal_Int32			_n5;
301 
302 	inline ExceptionType( typelib_TypeDescription * pTypeDescr ) throw ()
303 		: _n0( 0 )
304 		, _n1( 0 )
305 		, _n2( -1 )
306 		, _n3( 0 )
307 		, _n4( pTypeDescr->nSize )
308 		, _pCopyCtor( new ObjectFunction( pTypeDescr, copyConstruct ) )
309 		, _n5( 0 )
310 		{ _pTypeInfo = msci_getRTTI( pTypeDescr->pTypeName ); }
311 	inline ~ExceptionType() throw ()
312 		{ delete _pCopyCtor; }
313 };
314 //==================================================================================================
315 struct RaiseInfo
316 {
317 	sal_Int32			_n0;
318 	ObjectFunction *	_pDtor;
319 	sal_Int32			_n2;
320 	void *				_types;
321 	sal_Int32			_n3, _n4;
322 
323 	RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
324 	~RaiseInfo() throw ();
325 };
326 //__________________________________________________________________________________________________
327 RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
328 	: _n0( 0 )
329 	, _pDtor( new ObjectFunction( pTypeDescr, destruct ) )
330 	, _n2( 0 )
331 	, _n3( 0 )
332 	, _n4( 0 )
333 {
334 	// a must be
335 	OSL_ENSURE( sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer size differs from sal_Int32!" );
336 
337 	typelib_CompoundTypeDescription * pCompTypeDescr;
338 
339 	// info count
340 	sal_Int32 nLen = 0;
341 	for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
342 		  pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
343 	{
344 		++nLen;
345 	}
346 
347 	// info count accompanied by type info ptrs: type, base type, base base type, ...
348 	_types = ::rtl_allocateMemory( sizeof(sal_Int32) + (sizeof(ExceptionType *) * nLen) );
349 	*(sal_Int32 *)_types = nLen;
350 
351 	ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
352 
353 	sal_Int32 nPos = 0;
354 	for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
355 		  pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
356 	{
357 		ppTypes[nPos++] = new ExceptionType( (typelib_TypeDescription *)pCompTypeDescr );
358 	}
359 }
360 //__________________________________________________________________________________________________
361 RaiseInfo::~RaiseInfo() throw ()
362 {
363 	ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
364 	for ( sal_Int32 nTypes = *(sal_Int32 *)_types; nTypes--; )
365     {
366 		delete ppTypes[nTypes];
367     }
368 	::rtl_freeMemory( _types );
369 
370 	delete _pDtor;
371 }
372 
373 //==================================================================================================
374 class ExceptionInfos
375 {
376 	Mutex			_aMutex;
377 	t_string2PtrMap	_allRaiseInfos;
378 
379 public:
380 	static void * getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
381 
382 	ExceptionInfos() throw ();
383 	~ExceptionInfos() throw ();
384 };
385 //__________________________________________________________________________________________________
386 ExceptionInfos::ExceptionInfos() throw ()
387 {
388 }
389 //__________________________________________________________________________________________________
390 ExceptionInfos::~ExceptionInfos() throw ()
391 {
392 #if OSL_DEBUG_LEVEL > 1
393 	OSL_TRACE( "> freeing exception infos... <\n" );
394 #endif
395 
396 	MutexGuard aGuard( _aMutex );
397 	for ( t_string2PtrMap::const_iterator iPos( _allRaiseInfos.begin() );
398           iPos != _allRaiseInfos.end(); ++iPos )
399 	{
400 		delete (RaiseInfo *)iPos->second;
401 	}
402 }
403 //__________________________________________________________________________________________________
404 void * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
405 {
406 	static ExceptionInfos * s_pInfos = 0;
407 	if (! s_pInfos)
408 	{
409 		MutexGuard aGuard( Mutex::getGlobalMutex() );
410 		if (! s_pInfos)
411 		{
412 #ifdef LEAK_STATIC_DATA
413 			s_pInfos = new ExceptionInfos();
414 #else
415 			static ExceptionInfos s_allExceptionInfos;
416 			s_pInfos = &s_allExceptionInfos;
417 #endif
418 		}
419 	}
420 
421 	OSL_ASSERT( pTypeDescr &&
422                 (pTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
423                  pTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION) );
424 
425     void * pRaiseInfo;
426 
427     OUString const & rTypeName = *reinterpret_cast< OUString * >( &pTypeDescr->pTypeName );
428 	MutexGuard aGuard( s_pInfos->_aMutex );
429 	t_string2PtrMap::const_iterator const iFind(
430         s_pInfos->_allRaiseInfos.find( rTypeName ) );
431     if (iFind == s_pInfos->_allRaiseInfos.end())
432     {
433         pRaiseInfo = new RaiseInfo( pTypeDescr );
434         // put into map
435 		pair< t_string2PtrMap::iterator, bool > insertion(
436             s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, pRaiseInfo ) ) );
437         OSL_ENSURE( insertion.second, "### raise info insertion failed?!" );
438     }
439     else
440     {
441         // reuse existing info
442         pRaiseInfo = iFind->second;
443     }
444 
445     return pRaiseInfo;
446 }
447 
448 
449 //##################################################################################################
450 //#### exported ####################################################################################
451 //##################################################################################################
452 
453 
454 //##################################################################################################
455 type_info * msci_getRTTI( OUString const & rUNOname )
456 {
457 	static RTTInfos * s_pRTTIs = 0;
458 	if (! s_pRTTIs)
459 	{
460 		MutexGuard aGuard( Mutex::getGlobalMutex() );
461 		if (! s_pRTTIs)
462 		{
463 #ifdef LEAK_STATIC_DATA
464 			s_pRTTIs = new RTTInfos();
465 #else
466 			static RTTInfos s_aRTTIs;
467 			s_pRTTIs = &s_aRTTIs;
468 #endif
469 		}
470 	}
471 	return s_pRTTIs->getRTTI( rUNOname );
472 }
473 
474 //##################################################################################################
475 void msci_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
476 {
477     // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
478     // thus this obj file will be compiled without opt, so no inling of
479     // ExceptionInfos::getRaiseInfo()
480 
481 	// construct cpp exception object
482 	typelib_TypeDescription * pTypeDescr = 0;
483 	TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
484 
485 	void * pCppExc = alloca( pTypeDescr->nSize );
486 	::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
487 
488 	// a must be
489 	OSL_ENSURE(
490         sizeof(sal_Int32) == sizeof(void *),
491         "### pointer size differs from sal_Int32!" );
492 	DWORD arFilterArgs[3];
493 	arFilterArgs[0] = MSVC_magic_number;
494 	arFilterArgs[1] = (DWORD)pCppExc;
495     arFilterArgs[2] = (DWORD)ExceptionInfos::getRaiseInfo( pTypeDescr );
496 
497 	// destruct uno exception
498 	::uno_any_destruct( pUnoExc, 0 );
499 	TYPELIB_DANGER_RELEASE( pTypeDescr );
500 
501 	// last point to release anything not affected by stack unwinding
502 	RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 3, arFilterArgs );
503 }
504 
505 //##############################################################################
506 int msci_filterCppException(
507 	EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
508 {
509 	if (pPointers == 0)
510         return EXCEPTION_CONTINUE_SEARCH;
511 	EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord;
512     // handle only C++ exceptions:
513 	if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
514         return EXCEPTION_CONTINUE_SEARCH;
515 
516 #if _MSC_VER < 1300 // MSVC -6
517     bool rethrow = (pRecord->NumberParameters < 3 ||
518                     pRecord->ExceptionInformation[ 2 ] == 0);
519 #else
520     bool rethrow = __CxxDetectRethrow( &pRecord );
521     OSL_ASSERT( pRecord == pPointers->ExceptionRecord );
522 #endif
523     if (rethrow && pRecord == pPointers->ExceptionRecord)
524     {
525         // hack to get msvcrt internal _curexception field:
526         pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(
527             reinterpret_cast< char * >( __pxcptinfoptrs() ) +
528             // as long as we don't demand msvcr source as build prerequisite
529             // (->platform sdk), we have to code those offsets here.
530             //
531             // crt\src\mtdll.h:
532             // offsetof (_tiddata, _curexception) -
533             // offsetof (_tiddata, _tpxcptinfoptrs):
534 #if _MSC_VER < 1300
535             0x18 // msvcrt,dll
536 #elif _MSC_VER < 1310
537             0x20 // msvcr70.dll
538 #elif _MSC_VER < 1400
539             0x24 // msvcr71.dll
540 #else
541             0x28 // msvcr80.dll
542 #endif
543             );
544     }
545     // rethrow: handle only C++ exceptions:
546 	if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
547         return EXCEPTION_CONTINUE_SEARCH;
548 
549     if (pRecord->NumberParameters == 3 &&
550 //  		pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
551 		pRecord->ExceptionInformation[ 1 ] != 0 &&
552 		pRecord->ExceptionInformation[ 2 ] != 0)
553 	{
554 		void * types = reinterpret_cast< RaiseInfo * >(
555             pRecord->ExceptionInformation[ 2 ] )->_types;
556 		if (types != 0 && *reinterpret_cast< DWORD * >( types ) > 0) // count
557 		{
558 			ExceptionType * pType = *reinterpret_cast< ExceptionType ** >(
559                 reinterpret_cast< DWORD * >( types ) + 1 );
560 			if (pType != 0 && pType->_pTypeInfo != 0)
561 			{
562                 OUString aRTTIname(
563                     OStringToOUString(
564                         reinterpret_cast< __type_info * >(
565                             pType->_pTypeInfo )->_m_d_name,
566                         RTL_TEXTENCODING_ASCII_US ) );
567 				OUString aUNOname( toUNOname( aRTTIname ) );
568 
569 				typelib_TypeDescription * pExcTypeDescr = 0;
570 				typelib_typedescription_getByName(
571                     &pExcTypeDescr, aUNOname.pData );
572 				if (pExcTypeDescr == 0)
573 				{
574                     OUStringBuffer buf;
575                     buf.appendAscii(
576                         RTL_CONSTASCII_STRINGPARAM(
577                             "[msci_uno bridge error] UNO type of "
578                             "C++ exception unknown: \"") );
579                     buf.append( aUNOname );
580                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
581                                          "\", RTTI-name=\"") );
582                     buf.append( aRTTIname );
583                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
584                     RuntimeException exc(
585                         buf.makeStringAndClear(), Reference< XInterface >() );
586                     uno_type_any_constructAndConvert(
587                         pUnoExc, &exc,
588                         ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
589 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
590                     // if (! rethrow):
591                     // though this unknown exception leaks now, no user-defined
592                     // exception is ever thrown thru the binary C-UNO dispatcher
593                     // call stack.
594 #endif
595 				}
596 				else
597 				{
598 					// construct uno exception any
599 					uno_any_constructAndConvert(
600 						pUnoExc, (void *) pRecord->ExceptionInformation[1],
601 						pExcTypeDescr, pCpp2Uno );
602 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
603                     if (! rethrow)
604                     {
605                         uno_destructData(
606                             (void *) pRecord->ExceptionInformation[1],
607                             pExcTypeDescr, cpp_release );
608                     }
609 #endif
610 					typelib_typedescription_release( pExcTypeDescr );
611 				}
612 
613 				return EXCEPTION_EXECUTE_HANDLER;
614 			}
615 		}
616 	}
617     // though this unknown exception leaks now, no user-defined exception
618     // is ever thrown thru the binary C-UNO dispatcher call stack.
619     RuntimeException exc(
620         OUString( RTL_CONSTASCII_USTRINGPARAM(
621                       "[msci_uno bridge error] unexpected "
622                       "C++ exception occured!") ),
623         Reference< XInterface >() );
624     uno_type_any_constructAndConvert(
625         pUnoExc, &exc, ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
626     return EXCEPTION_EXECUTE_HANDLER;
627 }
628 
629 }
630 
631 #pragma pack(pop)
632 
633