1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
32 #include <com/sun/star/uno/genfunc.hxx>
35 #include "bridges/cpp_uno/shared/bridge.hxx"
36 #include "bridges/cpp_uno/shared/types.hxx"
37 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
38 #include "bridges/cpp_uno/shared/vtables.hxx"
42 #if OSL_DEBUG_LEVEL > 1
46 using namespace ::rtl
;
47 using namespace ::com::sun::star::uno
;
53 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
54 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
55 typelib_TypeDescriptionReference
* pReturnTypeRef
,
57 typelib_MethodParameter
* pParams
,
60 uno_Any
** ppUnoExc
) throw ()
62 const int MAXPARAMS
= 20;
64 if ( nParams
> MAXPARAMS
)
66 // We have a hard limit on the number of parameters so that we
67 // don't need any assembler code here but can call the
68 // function using normal C++.
73 // Table with this pointer, optional complex return value ptr, and the parameters
78 } aCppParams
[MAXPARAMS
+2], uRetVal
;
79 int nCppParamIndex
= 0;
82 typelib_TypeDescription
* pReturnTD
= NULL
;
83 TYPELIB_DANGER_GET( &pReturnTD
, pReturnTypeRef
);
84 OSL_ENSURE( pReturnTD
, "### expected return type description!" );
87 void * pAdjustedThisPtr
= (void **)( pThis
->getCppI() ) + aVtableSlot
.offset
;
88 aCppParams
[nCppParamIndex
++].p
= pAdjustedThisPtr
;
90 bool bSimpleReturn
= true;
93 if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD
) )
95 // Complex return via ptr
96 bSimpleReturn
= false;
97 aCppParams
[nCppParamIndex
++].p
=
98 bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTD
)?
99 alloca( pReturnTD
->nSize
) : pUnoReturn
;
103 // Indexes of values this have to be converted (interface conversion C++<=>UNO)
104 int pTempCppIndexes
[MAXPARAMS
];
105 int pTempIndexes
[MAXPARAMS
];
106 int nTempIndexes
= 0;
108 // Type descriptions for reconversions
109 typelib_TypeDescription
*pTempParamTypeDescr
[MAXPARAMS
];
111 for ( int nPos
= 0; nPos
< nParams
; ++nPos
, ++nCppParamIndex
)
113 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
115 typelib_TypeDescription
* pParamTD
= NULL
;
116 TYPELIB_DANGER_GET( &pParamTD
, rParam
.pTypeRef
);
119 bridges::cpp_uno::shared::isSimpleType( pParamTD
) )
121 ::uno_copyAndConvertData(
122 &aCppParams
[nCppParamIndex
], pUnoArgs
[nPos
], pParamTD
,
123 pThis
->getBridge()->getUno2Cpp() );
126 TYPELIB_DANGER_RELEASE( pParamTD
);
128 else // Ptr to complex value | ref
130 if ( !rParam
.bIn
) // Is pure out
132 // C++ out is constructed mem, UNO out is not!
134 aCppParams
[nCppParamIndex
].p
= alloca( pParamTD
->nSize
),
137 pTempCppIndexes
[nTempIndexes
] = nCppParamIndex
;
138 pTempIndexes
[nTempIndexes
] = nPos
;
140 // Will be released at reconversion
141 pTempParamTypeDescr
[nTempIndexes
++] = pParamTD
;
145 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD
) )
147 ::uno_copyAndConvertData(
148 aCppParams
[nCppParamIndex
].p
= alloca( pParamTD
->nSize
),
149 pUnoArgs
[nPos
], pParamTD
,
150 pThis
->getBridge()->getUno2Cpp() );
152 pTempCppIndexes
[nTempIndexes
] = nCppParamIndex
;
153 pTempIndexes
[nTempIndexes
] = nPos
;
155 // Will be released at reconversion
156 pTempParamTypeDescr
[nTempIndexes
++] = pParamTD
;
160 aCppParams
[nCppParamIndex
].p
= pUnoArgs
[nPos
];
163 TYPELIB_DANGER_RELEASE( pParamTD
);
170 // The first real parameter is always 'this'.
172 // The Windows x64 calling convention is very regular and
173 // elegant (even if perhaps then slightly slower than the
174 // Linux x64 one): The first four parameters, never more, are
175 // passed in registers, as long as they are a qword in size
176 // or less. (If larger, a pointer to a temp copy is passed, so
177 // it's equivalent anyway.) Floating point values are passed
178 // in XMM0..3 registers, others in RCX, RDX, R8, R9.
180 // Now, the nice thing for us is that when calling varargs
181 // functions, floating-point parameters among the four first
182 // ones are always passed *both* in an XMM and integer
183 // register. So we don't need to bother here calling the
184 // method different ways depending on what types of parameters
185 // it actually expects. We just pretend parameters 3..4 are
186 // doubles, and they will be passed both in XMM and integer
187 // registers, and the callee will find them where it
188 // expects. (The callee is not actually varargs, of course.)
190 sal_Int64 (*pIMethod
)(sal_Int64
, ...) =
191 (sal_Int64 (*)(sal_Int64
, ...))
192 (*((sal_uInt64
**)pAdjustedThisPtr
))[aVtableSlot
.index
];
194 double (*pFMethod
)(sal_Int64
, ...) =
195 (double (*)(sal_Int64
, ...))
196 (*((sal_uInt64
**)pAdjustedThisPtr
))[aVtableSlot
.index
];
198 // Pass parameters 2..4 as if it was a floating-point value so
199 // that it gets put in both XMM and integer registers per the
200 // calling convention. It doesn't matter if it actually is a
204 (pReturnTD
->eTypeClass
== typelib_TypeClass_FLOAT
||
205 pReturnTD
->eTypeClass
== typelib_TypeClass_DOUBLE
) )
207 pFMethod (aCppParams
[0].i
, aCppParams
[1].d
, aCppParams
[2].d
, aCppParams
[3].d
,
208 aCppParams
[4].i
, aCppParams
[5].i
, aCppParams
[6].i
, aCppParams
[7].i
,
209 aCppParams
[8].i
, aCppParams
[9].i
, aCppParams
[10].i
, aCppParams
[11].i
,
210 aCppParams
[12].i
, aCppParams
[13].i
, aCppParams
[14].i
, aCppParams
[15].i
,
211 aCppParams
[16].i
, aCppParams
[17].i
, aCppParams
[18].i
, aCppParams
[19].i
);
214 pIMethod (aCppParams
[0].i
, aCppParams
[1].d
, aCppParams
[2].d
, aCppParams
[3].d
,
215 aCppParams
[4].i
, aCppParams
[5].i
, aCppParams
[6].i
, aCppParams
[7].i
,
216 aCppParams
[8].i
, aCppParams
[9].i
, aCppParams
[10].i
, aCppParams
[11].i
,
217 aCppParams
[12].i
, aCppParams
[13].i
, aCppParams
[14].i
, aCppParams
[15].i
,
218 aCppParams
[16].i
, aCppParams
[17].i
, aCppParams
[18].i
, aCppParams
[19].i
);
220 __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException(
221 GetExceptionInformation(),
222 *ppUnoExc
, pThis
->getBridge()->getCpp2Uno() ))
224 // *ppUnoExc was constructed by filter function.
226 while ( nTempIndexes
-- )
228 int nCppIndex
= pTempCppIndexes
[nTempIndexes
];
229 // Destroy temp C++ param => C++: every param was constructed
231 aCppParams
[nCppIndex
].p
, pTempParamTypeDescr
[nTempIndexes
],
233 TYPELIB_DANGER_RELEASE( pTempParamTypeDescr
[nTempIndexes
] );
237 TYPELIB_DANGER_RELEASE( pReturnTD
);
243 // No exception occurred
246 // Reconvert temporary params
247 while ( nTempIndexes
-- )
249 int nCppIndex
= pTempCppIndexes
[nTempIndexes
];
250 int nIndex
= pTempIndexes
[nTempIndexes
];
251 typelib_TypeDescription
* pParamTD
=
252 pTempParamTypeDescr
[nTempIndexes
];
254 if ( pParams
[nIndex
].bIn
)
256 if ( pParams
[nIndex
].bOut
) // Inout
259 pUnoArgs
[nIndex
], pParamTD
, 0 ); // Destroy UNO value
260 ::uno_copyAndConvertData(
261 pUnoArgs
[nIndex
], aCppParams
[nCppIndex
].p
, pParamTD
,
262 pThis
->getBridge()->getCpp2Uno() );
267 ::uno_copyAndConvertData(
268 pUnoArgs
[nIndex
], aCppParams
[nCppIndex
].p
, pParamTD
,
269 pThis
->getBridge()->getCpp2Uno() );
272 // Destroy temp C++ param => C++: every param was constructed
274 aCppParams
[nCppIndex
].p
, pParamTD
, cpp_release
);
276 TYPELIB_DANGER_RELEASE( pParamTD
);
280 if ( !bSimpleReturn
)
282 ::uno_copyAndConvertData(
283 pUnoReturn
, uRetVal
.p
, pReturnTD
,
284 pThis
->getBridge()->getCpp2Uno() );
286 aCppParams
[1].p
, pReturnTD
, cpp_release
);
288 else if ( pUnoReturn
)
289 *(sal_Int64
*)pUnoReturn
= uRetVal
.i
;
292 TYPELIB_DANGER_RELEASE( pReturnTD
);
299 namespace bridges
{ namespace cpp_uno
{ namespace shared
{
301 void unoInterfaceProxyDispatch(
302 uno_Interface
* pUnoI
,
303 const typelib_TypeDescription
* pMemberTD
,
306 uno_Any
** ppException
)
309 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
310 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
* >(pUnoI
);
311 #if OSL_DEBUG_LEVEL > 0
312 typelib_InterfaceTypeDescription
* pTypeDescr
= pThis
->pTypeDescr
;
315 switch (pMemberTD
->eTypeClass
)
317 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
319 #if OSL_DEBUG_LEVEL > 0
320 // determine vtable call index
321 sal_Int32 nMemberPos
= ((typelib_InterfaceMemberTypeDescription
*)pMemberTD
)->nPosition
;
322 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### member pos out of range!" );
324 VtableSlot
aVtableSlot(
327 typelib_InterfaceAttributeTypeDescription
const * >(
334 ((typelib_InterfaceAttributeTypeDescription
*)pMemberTD
)->pAttributeTypeRef
,
335 0, NULL
, // no params
336 pReturn
, pArgs
, ppException
);
341 typelib_MethodParameter aParam
;
343 ((typelib_InterfaceAttributeTypeDescription
*)pMemberTD
)->pAttributeTypeRef
;
344 aParam
.bIn
= sal_True
;
345 aParam
.bOut
= sal_False
;
347 typelib_TypeDescriptionReference
* pReturnTypeRef
= NULL
;
348 OUString
aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
349 typelib_typedescriptionreference_new(
350 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
352 aVtableSlot
.index
+= 1; // get, then set method
357 pReturn
, pArgs
, ppException
);
359 typelib_typedescriptionreference_release( pReturnTypeRef
);
364 case typelib_TypeClass_INTERFACE_METHOD
:
366 #if OSL_DEBUG_LEVEL > 0
367 // determine vtable call index
368 sal_Int32 nMemberPos
= ((typelib_InterfaceMemberTypeDescription
*)pMemberTD
)->nPosition
;
369 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### member pos out of range!" );
371 VtableSlot
aVtableSlot(
374 typelib_InterfaceMethodTypeDescription
const * >(
377 switch (aVtableSlot
.index
)
380 case 1: // Acquire UNO interface
381 (*pUnoI
->acquire
)( pUnoI
);
384 case 2: // Release UNO interface
385 (*pUnoI
->release
)( pUnoI
);
388 case 0: // queryInterface() opt
390 typelib_TypeDescription
* pTD
= NULL
;
391 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
395 uno_Interface
* pInterface
= NULL
;
396 (*pThis
->getBridge()->getUnoEnv()->getRegisteredInterface
)(
397 pThis
->getBridge()->getUnoEnv(),
398 (void **)&pInterface
, pThis
->oid
.pData
, (typelib_InterfaceTypeDescription
*)pTD
);
403 reinterpret_cast< uno_Any
* >( pReturn
),
404 &pInterface
, pTD
, 0 );
405 (*pInterface
->release
)( pInterface
);
407 TYPELIB_DANGER_RELEASE( pTD
);
412 TYPELIB_DANGER_RELEASE( pTD
);
414 } // Else perform queryInterface()
418 ((typelib_InterfaceMethodTypeDescription
*)pMemberTD
)->pReturnTypeRef
,
419 ((typelib_InterfaceMethodTypeDescription
*)pMemberTD
)->nParams
,
420 ((typelib_InterfaceMethodTypeDescription
*)pMemberTD
)->pParams
,
421 pReturn
, pArgs
, ppException
) )
423 RuntimeException
aExc(
424 OUString( RTL_CONSTASCII_USTRINGPARAM("Too many parameters!") ),
425 Reference
< XInterface
>() );
427 Type
const & rExcType
= ::getCppuType( &aExc
);
428 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), 0 );
435 RuntimeException
aExc(
436 OUString( RTL_CONSTASCII_USTRINGPARAM("Illegal member type description!") ),
437 Reference
< XInterface
>() );
439 Type
const & rExcType
= ::getCppuType( &aExc
);
440 // Binary identical null reference (whatever that comment means...)
441 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), 0 );
448 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */