1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
25 #include <sal/alloca.h>
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include <com/sun/star/uno/Exception.hpp>
29 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <o3tl/runtimetooustring.hxx>
35 #include <unointerfaceproxy.hxx>
36 #include <vtables.hxx>
38 #include "callvirtualmethod.hxx"
41 using namespace ::com::sun::star::uno
;
47 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
48 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
49 typelib_TypeDescriptionReference
* pReturnTypeRef
,
50 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
51 void * pUnoReturn
, void * pUnoArgs
[], uno_Any
** ppUnoExc
)
53 // max space for: [complex ret ptr], values|ptr ...
55 static_cast<char *>(alloca( sizeof(sal_Int32
) + ((nParams
+2) * sizeof(sal_Int64
)) ));
56 char * pCppStackStart
= pCppStack
;
59 typelib_TypeDescription
* pReturnTypeDescr
= nullptr;
60 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
61 assert(pReturnTypeDescr
);
63 void * pCppReturn
= nullptr; // if != 0 && != pUnoReturn, needs reconversion
64 bool bSimpleReturn
= true;
68 bSimpleReturn
= x86::isSimpleReturnType(pReturnTypeDescr
);
71 pCppReturn
= pUnoReturn
; // direct way for simple types
75 // complex return via ptr
76 pCppReturn
= *reinterpret_cast<void **>(pCppStack
)
77 = (bridges::cpp_uno::shared::relatesToInterfaceType(
79 ? alloca( pReturnTypeDescr
->nSize
)
80 : pUnoReturn
); // direct way
81 pCppStack
+= sizeof(void *);
85 void * pAdjustedThisPtr
= reinterpret_cast< void ** >(pThis
->getCppI())
87 *reinterpret_cast<void **>(pCppStack
) = pAdjustedThisPtr
;
88 pCppStack
+= sizeof( void* );
91 static_assert(sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!");
93 void ** pCppArgs
= static_cast<void **>(alloca( 3 * sizeof(void *) * nParams
));
94 // indices of values this have to be converted (interface conversion cpp<=>uno)
95 sal_Int32
* pTempIndices
= reinterpret_cast<sal_Int32
*>(pCppArgs
+ nParams
);
96 // type descriptions for reconversions
97 typelib_TypeDescription
** ppTempParamTypeDescr
= reinterpret_cast<typelib_TypeDescription
**>(pCppArgs
+ (2 * nParams
));
99 sal_Int32 nTempIndices
= 0;
101 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
103 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
104 typelib_TypeDescription
* pParamTypeDescr
= nullptr;
105 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
108 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
110 uno_copyAndConvertData( pCppArgs
[nPos
] = pCppStack
, pUnoArgs
[nPos
], pParamTypeDescr
,
111 pThis
->getBridge()->getUno2Cpp() );
113 switch (pParamTypeDescr
->eTypeClass
)
115 case typelib_TypeClass_HYPER
:
116 case typelib_TypeClass_UNSIGNED_HYPER
:
117 case typelib_TypeClass_DOUBLE
:
118 pCppStack
+= sizeof(sal_Int32
); // extra long
124 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
126 else // ptr to complex value | ref
128 if (! rParam
.bIn
) // is pure out
130 // cpp out is constructed mem, uno out is not!
132 *reinterpret_cast<void **>(pCppStack
) = pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
134 pTempIndices
[nTempIndices
] = nPos
; // default constructed for cpp call
135 // will be released at reconversion
136 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
139 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
142 uno_copyAndConvertData(
143 *reinterpret_cast<void **>(pCppStack
) = pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
144 pUnoArgs
[nPos
], pParamTypeDescr
,
145 pThis
->getBridge()->getUno2Cpp() );
147 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
148 // will be released at reconversion
149 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
153 *reinterpret_cast<void **>(pCppStack
) = pCppArgs
[nPos
] = pUnoArgs
[nPos
];
155 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
158 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
163 assert( !( (pCppStack
- pCppStackStart
) & 3) && "UNALIGNED STACK !!! (Please DO panic)" );
165 CPPU_CURRENT_NAMESPACE::callVirtualMethod(
166 pAdjustedThisPtr
, aVtableSlot
.index
,
167 pCppReturn
, pReturnTypeDescr
, bSimpleReturn
,
168 reinterpret_cast<sal_Int32
*>(pCppStackStart
), (pCppStack
- pCppStackStart
) / sizeof(sal_Int32
) );
169 } catch (css::uno::Exception
&) {
171 } catch (std::exception
& e
) {
172 throw css::uno::RuntimeException(
173 "C++ code threw " + o3tl::runtimeToOUString(typeid(e
).name()) + ": "
174 + o3tl::runtimeToOUString(e
.what()));
176 throw css::uno::RuntimeException("C++ code threw unknown exception");
178 // NO exception occurred...
181 // reconvert temporary params
182 for ( ; nTempIndices
--; )
184 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
185 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
187 if (pParams
[nIndex
].bIn
)
189 if (pParams
[nIndex
].bOut
) // inout
191 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, nullptr ); // destroy uno value
192 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
193 pThis
->getBridge()->getCpp2Uno() );
198 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
199 pThis
->getBridge()->getCpp2Uno() );
201 // destroy temp cpp param => cpp: every param was constructed
202 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
204 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
207 if (pCppReturn
&& pUnoReturn
!= pCppReturn
)
209 uno_copyAndConvertData( pUnoReturn
, pCppReturn
, pReturnTypeDescr
,
210 pThis
->getBridge()->getCpp2Uno() );
211 uno_destructData( pCppReturn
, pReturnTypeDescr
, cpp_release
);
216 // fill uno exception
217 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc
, pThis
->getBridge()->getCpp2Uno());
220 for ( ; nTempIndices
--; )
222 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
223 // destroy temp cpp param => cpp: every param was constructed
224 uno_destructData( pCppArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], cpp_release
);
225 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
228 if (pReturnTypeDescr
)
229 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
237 bool isSimpleReturnType(typelib_TypeDescription
* pTD
, bool recursive
)
239 if (bridges::cpp_uno::shared::isSimpleType( pTD
))
241 #if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \
242 defined(MACOSX) || defined(DRAGONFLY)
243 // Only structs of exactly 1, 2, 4, or 8 bytes are returned through
244 // registers, see <http://developer.apple.com/documentation/DeveloperTools/
245 // Conceptual/LowLevelABI/Articles/IA32.html>:
246 if (pTD
->eTypeClass
== typelib_TypeClass_STRUCT
&&
247 (recursive
|| pTD
->nSize
<= 2 || pTD
->nSize
== 4 || pTD
->nSize
== 8))
249 typelib_CompoundTypeDescription
*const pCompTD
=
250 (typelib_CompoundTypeDescription
*) pTD
;
251 for ( sal_Int32 pos
= pCompTD
->nMembers
; pos
--; ) {
252 typelib_TypeDescription
* pMemberTD
= 0;
253 TYPELIB_DANGER_GET( &pMemberTD
, pCompTD
->ppTypeRefs
[pos
] );
254 bool const b
= isSimpleReturnType(pMemberTD
, true);
255 TYPELIB_DANGER_RELEASE( pMemberTD
);
268 namespace bridges::cpp_uno::shared
{
270 void unoInterfaceProxyDispatch(
271 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberDescr
,
272 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
275 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
276 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
* >(pUnoI
);
278 switch (pMemberDescr
->eTypeClass
)
280 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
282 VtableSlot
aVtableSlot(
285 typelib_InterfaceAttributeTypeDescription
const * >(
289 // dependent dispatch
292 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
const *>(pMemberDescr
)->pAttributeTypeRef
,
293 0, nullptr, // no params
294 pReturn
, pArgs
, ppException
);
299 typelib_MethodParameter aParam
;
301 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
const *>(pMemberDescr
)->pAttributeTypeRef
;
305 typelib_TypeDescriptionReference
* pReturnTypeRef
= nullptr;
306 OUString
aVoidName("void");
307 typelib_typedescriptionreference_new(
308 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
310 // dependent dispatch
311 aVtableSlot
.index
+= 1; // get, then set method
316 pReturn
, pArgs
, ppException
);
318 typelib_typedescriptionreference_release( pReturnTypeRef
);
323 case typelib_TypeClass_INTERFACE_METHOD
:
325 VtableSlot
aVtableSlot(
328 typelib_InterfaceMethodTypeDescription
const * >(
330 switch (aVtableSlot
.index
)
333 case 1: // acquire uno interface
334 (*pUnoI
->acquire
)( pUnoI
);
335 *ppException
= nullptr;
337 case 2: // release uno interface
338 (*pUnoI
->release
)( pUnoI
);
339 *ppException
= nullptr;
341 case 0: // queryInterface() opt
343 typelib_TypeDescription
* pTD
= nullptr;
344 TYPELIB_DANGER_GET( &pTD
, static_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
347 uno_Interface
* pInterface
= nullptr;
348 (*pThis
->pBridge
->getUnoEnv()->getRegisteredInterface
)(
349 pThis
->pBridge
->getUnoEnv(),
350 reinterpret_cast<void **>(&pInterface
), pThis
->oid
.pData
, reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
) );
355 static_cast< uno_Any
* >( pReturn
),
356 &pInterface
, pTD
, nullptr );
357 (*pInterface
->release
)( pInterface
);
358 TYPELIB_DANGER_RELEASE( pTD
);
359 *ppException
= nullptr;
362 TYPELIB_DANGER_RELEASE( pTD
);
364 [[fallthrough
]]; // else perform queryInterface()
367 // dependent dispatch
370 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->pReturnTypeRef
,
371 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->nParams
,
372 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->pParams
,
373 pReturn
, pArgs
, ppException
);
379 ::com::sun::star::uno::RuntimeException
aExc(
380 "illegal member type description!",
381 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>() );
383 Type
const & rExcType
= cppu::UnoType
<decltype(aExc
)>::get();
384 // binary identical null reference
385 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), nullptr );
392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */