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 
35 using namespace ::com::sun::star;
36 
37 static 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 
215 typelib_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: */
sal_Int32 nIndex
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, or might contain entities of interface type).
Definition: types.cxx:41
typelib_TypeClass __cdecl cpp_mediate(void **pCallStack, const sal_Int32 nFunctionIndex, const sal_Int32 nVtableOffset, sal_Int64 *const pRegisterReturn)
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
void msvc_raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
typelib_InterfaceTypeDescription * getTypeDescr()
A cpp proxy wrapping a uno interface.
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
#define SAL_INFO(area, stream)
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 * p
#define SAL_WARN(area, stream)
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
sal_uInt16 nPos