LibreOffice Module bridges (master) 1
msvc_shared/cpp2uno.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 <malloc.h>
21
22#include <com/sun/star/uno/genfunc.hxx>
23#include <sal/log.hxx>
24#include <uno/data.h>
25#include <typelib/typedescription.hxx>
26
27#include <bridge.hxx>
28#include <cppinterfaceproxy.hxx>
29#include <types.hxx>
30#include <vtablefactory.hxx>
31
32#include <msvc/except.hxx>
33#include <msvc/cpp2uno.hxx>
34
35using namespace ::com::sun::star;
36
37static typelib_TypeClass
39 const typelib_TypeDescription* pMemberTD,
40 typelib_TypeDescriptionReference* pReturnTypeRef, // nullptr indicates void return
41 const sal_Int32 nParams, typelib_MethodParameter* pParams, void** pCallStack,
42 void** const pReturnAddr)
43{
44 // return type
45 typelib_TypeDescription* pReturnTD = nullptr;
46 if (pReturnTypeRef)
47 TYPELIB_DANGER_GET(&pReturnTD, pReturnTypeRef);
48
49 // if we don't return via register, the first stack parameter is the return value
50 int nFirstRealParam = 2;
51 if (pReturnAddr == pCallStack)
52 ++nFirstRealParam;
53
54 void* pUnoReturn = nullptr;
55 // complex return ptr: if != nullptr && != pUnoReturn, reconversion needed
56 void* pCppReturn = nullptr;
57
58 if (pReturnTD)
59 {
61 pUnoReturn = pReturnAddr;
62 else
63 {
64 pCppReturn = pCallStack[nFirstRealParam++];
66 ? alloca(pReturnTD->nSize)
67 : pCppReturn);
68 }
69 }
70
71 // parameters passed to the UNO function
72 void** pUnoArgs = static_cast<void**>(alloca(sizeof(void*) * nParams));
73
74 // parameters received from C++
75 void** pCppArgs = static_cast<void**>(alloca(sizeof(void*) * nParams));
76
77 // TODO: switch to typedef std::pair<sal_Int32, typelib_TypeDescription*> ReconversationInfo;
78 sal_Int32 nTempIndex = 0;
79 // indexes of values this have to be converted (interface conversion C++<=>UNO)
80 sal_Int32* pTempIndexes = static_cast<sal_Int32*>(alloca(sizeof(sal_Int32) * nParams));
81 // type descriptions for reconversions
82 typelib_TypeDescription** ppTempParamTD
83 = static_cast<typelib_TypeDescription**>(alloca(sizeof(void*) * nParams));
84
85 for (std::pair<sal_Int32, void**> p(0, pCallStack + nFirstRealParam); p.first < nParams;
86 ++p.first, ++p.second)
87 {
88 const auto& nPos = p.first;
89 auto& pCppIncomingParams = p.second;
90
91 const typelib_MethodParameter& rParam = pParams[nPos];
92 typelib_TypeDescription* pParamTD = nullptr;
93 TYPELIB_DANGER_GET(&pParamTD, rParam.pTypeRef);
94
95 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
96 {
97 pCppArgs[nPos] = pCppIncomingParams;
98 pUnoArgs[nPos] = pCppIncomingParams;
99 if (sizeof(void*) == sizeof(sal_Int32)) // account 64bit types on 32bit arch
100 {
101 switch (pParamTD->eTypeClass)
102 {
103 case typelib_TypeClass_HYPER:
104 case typelib_TypeClass_UNSIGNED_HYPER:
105 case typelib_TypeClass_DOUBLE:
106 ++pCppIncomingParams;
107 break;
108 default:
109 break;
110 }
111 }
112 TYPELIB_DANGER_RELEASE(pParamTD);
113 }
114 else // ptr to complex value | ref
115 {
116 pCppArgs[nPos] = *pCppIncomingParams;
117
118 if (!rParam.bIn) // is pure out
119 {
120 // UNO out is unconstructed memory
121 pUnoArgs[nPos] = alloca(pParamTD->nSize);
122 // pParamTD will be released at reconversion
123 pTempIndexes[nTempIndex] = nPos;
124 ppTempParamTD[nTempIndex++] = pParamTD;
125 }
126 // is in/inout
128 {
129 ::uno_copyAndConvertData(pUnoArgs[nPos] = alloca(pParamTD->nSize),
130 *pCppIncomingParams, pParamTD,
131 pThis->getBridge()->getCpp2Uno());
132 // pParamTD will be released at reconversion
133 pTempIndexes[nTempIndex] = nPos;
134 ppTempParamTD[nTempIndex++] = pParamTD;
135 }
136 else // direct way
137 {
138 pUnoArgs[nPos] = *pCppIncomingParams;
139 TYPELIB_DANGER_RELEASE(pParamTD);
140 }
141 }
142 }
143
144 // ExceptionHolder
145 uno_Any aUnoExc; // Any will be constructed by callee
146 uno_Any* pUnoExc = &aUnoExc;
147
148 // invoke UNO dispatch call
149 pThis->getUnoI()->pDispatcher(pThis->getUnoI(), pMemberTD, pUnoReturn, pUnoArgs, &pUnoExc);
150
151 // in case an exception occurred...
152 if (pUnoExc)
153 {
154 // destruct temporary in/inout params
155 while (nTempIndex--)
156 {
157 const sal_Int32 nIndex = pTempIndexes[nTempIndex];
158 if (pParams[nIndex].bIn) // is in/inout => was constructed
159 ::uno_destructData(pUnoArgs[nIndex], ppTempParamTD[nTempIndex], nullptr);
160 TYPELIB_DANGER_RELEASE(ppTempParamTD[nTempIndex]);
161 }
162 if (pReturnTD)
163 TYPELIB_DANGER_RELEASE(pReturnTD);
164
165 msvc_raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp()); // has to destruct the any
166
167 // is here for dummy
168 return typelib_TypeClass_VOID;
169 }
170 else // no exception occurred...
171 {
172 // handle temporary params
173 while (nTempIndex--)
174 {
175 const sal_Int32 nIndex = pTempIndexes[nTempIndex];
176 typelib_TypeDescription* pParamTD = ppTempParamTD[nTempIndex];
177
178 if (pParams[nIndex].bOut) // inout/out
179 {
180 // convert and assign
181 ::uno_destructData(pCppArgs[nIndex], pParamTD, uno::cpp_release);
182 ::uno_copyAndConvertData(pCppArgs[nIndex], pUnoArgs[nIndex], pParamTD,
183 pThis->getBridge()->getUno2Cpp());
184 }
185 // destroy temp UNO param
186 ::uno_destructData(pUnoArgs[nIndex], pParamTD, nullptr);
187
188 TYPELIB_DANGER_RELEASE(pParamTD);
189 }
190
191 // handle return
192 if (pCppReturn) // has complex return
193 {
194 if (pUnoReturn != pCppReturn) // needs reconversion
195 {
196 ::uno_copyAndConvertData(pCppReturn, pUnoReturn, pReturnTD,
197 pThis->getBridge()->getUno2Cpp());
198 // destroy temp UNO return
199 ::uno_destructData(pUnoReturn, pReturnTD, nullptr);
200 }
201 *pReturnAddr = pCppReturn;
202 }
203
204 if (!pReturnTD)
205 return typelib_TypeClass_VOID;
206 else
207 {
208 typelib_TypeClass eRet = pReturnTD->eTypeClass;
209 TYPELIB_DANGER_RELEASE(pReturnTD);
210 return eRet;
211 }
212 }
213}
214
215typelib_TypeClass __cdecl cpp_mediate(void** pCallStack, const sal_Int32 nFunctionIndex,
216 const sal_Int32 nVtableOffset,
217 sal_Int64* const pRegisterReturn)
218{
219 // pCallStack:
220 // x64: ret value, ret adr, this, [complex ret *], cpp params
221 // x86: ret adr, this, [complex ret *], cpp params
222 //
223 // pRegisterReturn is just set on x86
224 // the return value is either the direct set for simply types, or it is set
225 // to "complex ret *" and the real return value is constructed at that memory.
226
227 // if we don't return via register, the first stack parameter is the return value
228 void** const pReturnAddr
229 = pRegisterReturn ? reinterpret_cast<void**>(pRegisterReturn) : pCallStack;
230
231 void* const pThis = static_cast<char*>(pCallStack[pRegisterReturn ? 1 : 2]) - nVtableOffset;
234
235 typelib_InterfaceTypeDescription* pInterfaceTD = pCppI->getTypeDescr();
236
237 SAL_INFO("bridges", "cpp_vtable_call: pCallStack=["
238 << std::hex << pCallStack[0] << "," << pCallStack[1] << ","
239 << pCallStack[2] << ",...], pThis=" << pThis << ", pCppI=" << pCppI
240 << std::dec << ", nFunctionIndex=" << nFunctionIndex
241 << ", nVtableOffset=" << nVtableOffset);
242 SAL_INFO("bridges", "name=" << OUString::unacquired(&pInterfaceTD->aBase.pTypeName));
243
244 if (nFunctionIndex >= pInterfaceTD->nMapFunctionIndexToMemberIndex)
245 {
246 OUString sError = "illegal " + OUString::unacquired(&pInterfaceTD->aBase.pTypeName)
247 + " vtable index " + OUString::number(nFunctionIndex) + "/"
248 + OUString::number(pInterfaceTD->nMapFunctionIndexToMemberIndex);
249 SAL_WARN("bridges", sError);
250 throw uno::RuntimeException(sError, static_cast<uno::XInterface*>(pThis));
251 }
252
253 // determine called method
254 sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[nFunctionIndex];
255 assert(nMemberPos < pInterfaceTD->nAllMembers);
256
257 uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
258
259 SAL_INFO("bridges", "Calling " << OUString::unacquired(&aMemberDescr.get()->pTypeName));
260
261 typelib_TypeClass eRet = typelib_TypeClass_VOID;
262 switch (aMemberDescr.get()->eTypeClass)
263 {
264 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
265 {
266 typelib_TypeDescriptionReference* pAttrTypeRef
267 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
268 ->pAttributeTypeRef;
269
270 if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
271 { // is GET method
272 eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pAttrTypeRef, 0, nullptr, pCallStack,
273 pReturnAddr);
274 }
275 else
276 { // is SET method
277 typelib_MethodParameter aParam;
278 aParam.pTypeRef = pAttrTypeRef;
279 aParam.bIn = true;
280 aParam.bOut = false;
281
282 eRet = cpp2uno_call(pCppI, aMemberDescr.get(), nullptr, 1, &aParam, pCallStack,
283 pReturnAddr);
284 }
285 break;
286 }
287 case typelib_TypeClass_INTERFACE_METHOD:
288 {
289 // is METHOD
290 switch (nFunctionIndex)
291 {
292 // standard XInterface vtable calls
293 case 1: // acquire()
294 pCppI->acquireProxy(); // non virtual call!
295 eRet = typelib_TypeClass_VOID;
296 break;
297 case 2: // release()
298 pCppI->releaseProxy(); // non virtual call!
299 eRet = typelib_TypeClass_VOID;
300 break;
301 case 0: // queryInterface() opt
302 {
303 const unsigned int nCppStackPos = (pReturnAddr == pCallStack) ? 4 : 3;
304 typelib_TypeDescription* pQueryTD = nullptr;
305 TYPELIB_DANGER_GET(
306 &pQueryTD,
307 static_cast<uno::Type*>(pCallStack[nCppStackPos])->getTypeLibType());
308 if (pQueryTD)
309 {
310 uno::XInterface* pInterface = nullptr;
311
312 pCppI->getBridge()->getCppEnv()->getRegisteredInterface(
313 pCppI->getBridge()->getCppEnv(), reinterpret_cast<void**>(&pInterface),
314 pCppI->getOid().pData,
315 reinterpret_cast<typelib_InterfaceTypeDescription*>(pQueryTD));
316
317 if (pInterface)
318 {
319 const unsigned int nReturnAddrPos = nCppStackPos - 1;
320 ::uno_any_construct(static_cast<uno_Any*>(pCallStack[nReturnAddrPos]),
321 &pInterface, pQueryTD, uno::cpp_acquire);
322 pInterface->release();
323 TYPELIB_DANGER_RELEASE(pQueryTD);
324
325 *pReturnAddr = pCallStack[nReturnAddrPos];
326 eRet = typelib_TypeClass_ANY;
327 break;
328 }
329 TYPELIB_DANGER_RELEASE(pQueryTD);
330 }
331 [[fallthrough]];
332 }
333 default: // perform queryInterface()
334 {
335 typelib_InterfaceMethodTypeDescription* pMethodTD
336 = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
337 aMemberDescr.get());
338
339 eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pMethodTD->pReturnTypeRef,
340 pMethodTD->nParams, pMethodTD->pParams, pCallStack,
341 pReturnAddr);
342 }
343 }
344 break;
345 }
346 default:
347 throw uno::RuntimeException("no member description found!",
348 static_cast<uno::XInterface*>(pThis));
349 }
350
351 return eRet;
352}
353
354/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
A cpp proxy wrapping a uno interface.
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
typelib_InterfaceTypeDescription * getTypeDescr()
sal_Int32 nIndex
void * p
sal_uInt16 nPos
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
struct _uno_Any uno_Any
Definition: msvc/except.hxx:32
typelib_TypeClass __cdecl cpp_mediate(void **pCallStack, const sal_Int32 nFunctionIndex, const sal_Int32 nVtableOffset, sal_Int64 *const pRegisterReturn)
static typelib_TypeClass cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy *pThis, const typelib_TypeDescription *pMemberTD, typelib_TypeDescriptionReference *pReturnTypeRef, const sal_Int32 nParams, typelib_MethodParameter *pParams, void **pCallStack, void **const pReturnAddr)
void msvc_raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT,...
Definition: types.cxx:28
bool relatesToInterfaceType(typelib_TypeDescription const *type)
Determines whether a type relates to an interface type (is itself an interface type,...
Definition: types.cxx:41