xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/uno2cpp.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26 
27 #include <malloc.h>
28 
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <uno/data.h>
31 
32 #include "bridges/cpp_uno/shared/bridge.hxx"
33 #include "bridges/cpp_uno/shared/types.hxx"
34 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
35 #include "bridges/cpp_uno/shared/vtables.hxx"
36 
37 #include "abi.hxx"
38 #include "mscx.hxx"
39 
40 using namespace ::rtl;
41 using namespace ::com::sun::star::uno;
42 
43 namespace
44 {
45 
46 //==================================================================================================
47 extern "C" void callVirtualMethod(
48     void * pAdjustedThisPtr, sal_Int32 nVtableIndex,
49     void * pRegisterReturn, typelib_TypeClass eReturnTypeClass,
50     sal_uInt64 * pStackLongs, sal_uInt32 nStackLongs );
51 
52 //==================================================================================================
53 static void cpp_call(
54     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
55     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
56     typelib_TypeDescriptionReference * pReturnTypeRef,
57     sal_Int32 nParams, typelib_MethodParameter * pParams,
58     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) throw ()
59 {
60     // max space for: [complex ret ptr], values|ptr ...
61     sal_uInt64 *pStack = (sal_uInt64 *)alloca( (nParams + 3) * sizeof(sal_uInt64) );
62     sal_uInt64 *pStackStart = pStack;
63 
64     // Push "this" pointer
65     void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
66     *pStack++ = *(sal_uInt64*)&pAdjustedThisPtr;
67 
68     // return
69     typelib_TypeDescription * pReturnTypeDescr = 0;
70     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
71     OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
72 
73     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
74 
75     if ( pReturnTypeDescr )
76     {
77         if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
78         {
79             // complex return via ptr
80             pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
81                          alloca( pReturnTypeDescr->nSize ) : pUnoReturn; // direct way
82             *pStack++ = *(sal_uInt64*)&pCppReturn;
83         }
84         else
85             pCppReturn = pUnoReturn; // direct way for simple types
86     }
87 
88     // Args
89     void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
90     // Indices of values this have to be converted (interface conversion cpp<=>uno)
91     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
92     // Type descriptions for reconversions
93     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
94 
95     sal_Int32 nTempIndizes = 0;
96 
97     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
98     {
99         const typelib_MethodParameter & rParam = pParams[nPos];
100         typelib_TypeDescription * pParamTypeDescr = 0;
101         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
102 
103         if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
104         {
105             uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
106                                     pThis->getBridge()->getUno2Cpp() );
107 
108             // pCppArgs[nPos] is the alloca(8) temp above, i.e. a POINTER to the
109             // converted value -- the value is *pCppArgs[nPos].  Using
110             // &pCppArgs[nPos] would read the array slot instead, passing the
111             // temp's address as the argument.  (That form is correct only in the
112             // complex/ref branch below, where the pointer IS the argument.)
113             switch (pParamTypeDescr->eTypeClass)
114             {
115             case typelib_TypeClass_HYPER:
116             case typelib_TypeClass_UNSIGNED_HYPER:
117                 *pStack++ = *(sal_uInt64*)pCppArgs[nPos];
118                 break;
119             case typelib_TypeClass_LONG:
120             case typelib_TypeClass_UNSIGNED_LONG:
121             case typelib_TypeClass_ENUM:
122                 *pStack++ = *(sal_uInt32*)pCppArgs[nPos];
123                 break;
124             case typelib_TypeClass_SHORT:
125             case typelib_TypeClass_UNSIGNED_SHORT:
126             case typelib_TypeClass_CHAR:
127                 *pStack++ = *(sal_uInt16*)pCppArgs[nPos];
128                 break;
129             case typelib_TypeClass_BOOLEAN:
130             case typelib_TypeClass_BYTE:
131                 *pStack++ = *(sal_uInt8*)pCppArgs[nPos];
132                 break;
133             case typelib_TypeClass_FLOAT:
134             case typelib_TypeClass_DOUBLE:
135                 *pStack++ = *(sal_uInt64*)pCppArgs[nPos]; // verbatim!
136                 break;
137             default:
138                 break;
139             }
140             // no longer needed
141             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
142         }
143         else // ptr to complex value | ref
144         {
145             if (! rParam.bIn) // is pure out
146             {
147                 // cpp out is constructed mem, uno out is not!
148                 uno_constructData(
149                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
150                     pParamTypeDescr );
151                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
152                 // will be released at reconversion
153                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
154             }
155             // is in/inout
156             else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
157             {
158                 uno_copyAndConvertData(
159                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
160                     pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
161 
162                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
163                 // will be released at reconversion
164                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
165             }
166             else // direct way
167             {
168                 pCppArgs[nPos] = pUnoArgs[nPos];
169                 // no longer needed
170                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
171             }
172             // here the POINTER is the argument (complex value passed by ref)
173             *pStack++ = (sal_uInt64)pCppArgs[nPos];
174         }
175     }
176 
177     __try
178     {
179         // pCppI is mscx this pointer
180         callVirtualMethod(
181             pAdjustedThisPtr,
182             aVtableSlot.index,
183             pCppReturn, pReturnTypeDescr->eTypeClass,
184             pStackStart, (pStack - pStackStart) );
185     }
186     __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException(
187                   GetExceptionInformation(),
188                   *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
189    {
190         // *ppUnoExc was constructed by filter function
191         // temporary params
192         for ( ; nTempIndizes--; )
193         {
194             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
195             // destroy temp cpp param => cpp: every param was constructed
196             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
197             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
198         }
199         // return type
200         if (pReturnTypeDescr)
201             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
202         // end here
203         return;
204     }
205 
206     // NO exception occurred
207     *ppUnoExc = 0;
208 
209     // reconvert temporary params
210     for ( ; nTempIndizes--; )
211     {
212         sal_Int32 nIndex = pTempIndizes[nTempIndizes];
213         typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
214 
215         if (pParams[nIndex].bIn)
216         {
217             if (pParams[nIndex].bOut) // inout
218             {
219                 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
220                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
221                                         pThis->getBridge()->getCpp2Uno() );
222             }
223         }
224         else // pure out
225         {
226             uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
227                                     pThis->getBridge()->getCpp2Uno() );
228         }
229         // destroy temp cpp param => cpp: every param was constructed
230         uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
231 
232         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
233     }
234     // return value
235     if (pCppReturn && pUnoReturn != pCppReturn)
236     {
237         uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
238                                 pThis->getBridge()->getCpp2Uno() );
239         uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
240     }
241     // return type
242     if (pReturnTypeDescr)
243         TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
244 }
245 
246 }
247 
248 namespace bridges { namespace cpp_uno { namespace shared {
249 
250 void unoInterfaceProxyDispatch(
251     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
252     void * pReturn, void * pArgs[], uno_Any ** ppException )
253 {
254     // is my surrogate
255     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
256         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
257 
258     switch (pMemberDescr->eTypeClass)
259     {
260     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
261     {
262         VtableSlot aVtableSlot(
263             getVtableSlot(
264                 reinterpret_cast<
265                     typelib_InterfaceAttributeTypeDescription const * >(
266                         pMemberDescr)));
267 
268         if (pReturn)
269         {
270             // dependent dispatch
271             cpp_call(
272                 pThis, aVtableSlot,
273                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
274                 0, 0, // no params
275                 pReturn, pArgs, ppException );
276         }
277         else
278         {
279             // is SET
280             typelib_MethodParameter aParam;
281             aParam.pTypeRef =
282                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
283             aParam.bIn      = sal_True;
284             aParam.bOut     = sal_False;
285 
286             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
287             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
288             typelib_typedescriptionreference_new(
289                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
290 
291             // dependent dispatch
292             aVtableSlot.index += 1; // get, then set method
293             cpp_call(
294                 pThis, aVtableSlot, // get, then set method
295                 pReturnTypeRef,
296                 1, &aParam,
297                 pReturn, pArgs, ppException );
298 
299             typelib_typedescriptionreference_release( pReturnTypeRef );
300         }
301 
302         break;
303     }
304     case typelib_TypeClass_INTERFACE_METHOD:
305     {
306         VtableSlot aVtableSlot(
307             getVtableSlot(
308                 reinterpret_cast<
309                     typelib_InterfaceMethodTypeDescription const * >(
310                         pMemberDescr)));
311 
312         switch (aVtableSlot.index)
313         {
314             // standard calls
315         case 1: // acquire uno interface
316             (*pUnoI->acquire)( pUnoI );
317             *ppException = 0;
318             break;
319         case 2: // release uno interface
320             (*pUnoI->release)( pUnoI );
321             *ppException = 0;
322             break;
323         case 0: // queryInterface() opt
324         {
325             typelib_TypeDescription * pTD = 0;
326             TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
327             if (pTD)
328             {
329                 uno_Interface * pInterface = 0;
330                 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
331                     pThis->getBridge()->getUnoEnv(),
332                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
333 
334                 if (pInterface)
335                 {
336                     ::uno_any_construct(
337                         reinterpret_cast< uno_Any * >( pReturn ),
338                         &pInterface, pTD, 0 );
339                     (*pInterface->release)( pInterface );
340                     TYPELIB_DANGER_RELEASE( pTD );
341                     *ppException = 0;
342                     break;
343                 }
344                 TYPELIB_DANGER_RELEASE( pTD );
345             }
346         } // else perform queryInterface()
347         default:
348             // dependent dispatch
349             cpp_call(
350                 pThis, aVtableSlot,
351                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
352                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
353                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
354                 pReturn, pArgs, ppException );
355         }
356         break;
357     }
358     default:
359     {
360         ::com::sun::star::uno::RuntimeException aExc(
361             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
362             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
363 
364         Type const & rExcType = ::getCppuType( &aExc );
365         // binary identical null reference
366         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
367     }
368     }
369 }
370 
371 } } }
372