xref: /AOO41X/main/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx (revision 129fa3d1fc5edc85a690d91de1660cefa4e8a95b)
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_cppu.hxx"
26 
27 #include "Proxy.hxx"
28 
29 #include "sal/alloca.h"
30 #include "uno/dispatcher.h"
31 #include "typelib/typedescription.hxx"
32 #include "cppu/EnvDcp.hxx"
33 
34 
35 //#define LOG_LIFECYCLE_Proxy
36 #ifdef LOG_LIFECYCLE_Proxy
37 #  include <iostream>
38 #  define LOG_LIFECYCLE_Proxy_emit(x) x
39 
40 #else
41 #  define LOG_LIFECYCLE_Proxy_emit(x)
42 
43 #endif
44 
45 
46 using namespace com::sun::star;
47 
48 
relatesToInterface(typelib_TypeDescription * pTypeDescr)49 static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
50     SAL_THROW( () )
51 {
52     switch (pTypeDescr->eTypeClass)
53     {
54 //      case typelib_TypeClass_TYPEDEF:
55     case typelib_TypeClass_SEQUENCE:
56     {
57         switch (((typelib_IndirectTypeDescription *)pTypeDescr)->pType->eTypeClass)
58         {
59         case typelib_TypeClass_INTERFACE:
60         case typelib_TypeClass_UNION: // might relate to interface
61         case typelib_TypeClass_ANY: // might relate to interface
62             return true;
63         case typelib_TypeClass_SEQUENCE:
64         case typelib_TypeClass_STRUCT:
65         case typelib_TypeClass_EXCEPTION:
66         {
67             typelib_TypeDescription * pTD = 0;
68             TYPELIB_DANGER_GET( &pTD, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
69             bool bRel = relatesToInterface( pTD );
70             TYPELIB_DANGER_RELEASE( pTD );
71             return bRel;
72         }
73         default:
74             ;
75         }
76         return false;
77     }
78     case typelib_TypeClass_STRUCT:
79     case typelib_TypeClass_EXCEPTION:
80     {
81         // ...optimized... to avoid getDescription() calls!
82         typelib_CompoundTypeDescription * pComp    = (typelib_CompoundTypeDescription *)pTypeDescr;
83         typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
84         for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
85         {
86             switch (pTypes[nPos]->eTypeClass)
87             {
88             case typelib_TypeClass_INTERFACE:
89             case typelib_TypeClass_UNION: // might relate to interface
90             case typelib_TypeClass_ANY: // might relate to interface
91                 return true;
92 //              case typelib_TypeClass_TYPEDEF:
93             case typelib_TypeClass_SEQUENCE:
94             case typelib_TypeClass_STRUCT:
95             case typelib_TypeClass_EXCEPTION:
96             {
97                 typelib_TypeDescription * pTD = 0;
98                 TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
99                 bool bRel = relatesToInterface( pTD );
100                 TYPELIB_DANGER_RELEASE( pTD );
101                 if (bRel)
102                     return true;
103             }
104             default:
105                 ;
106             }
107         }
108         if (pComp->pBaseTypeDescription)
109             return relatesToInterface( (typelib_TypeDescription *)pComp->pBaseTypeDescription );
110         break;
111     }
112     case typelib_TypeClass_UNION: // might relate to interface
113     case typelib_TypeClass_ANY: // might relate to interface
114     case typelib_TypeClass_INTERFACE:
115         return true;
116 
117     default:
118         ;
119     }
120     return false;
121 }
122 
s_Proxy_dispatch(uno_Interface * pUnoI,typelib_TypeDescription const * pMemberType,void * pReturn,void * pArgs[],uno_Any ** ppException)123 extern "C" { static void SAL_CALL s_Proxy_dispatch(
124     uno_Interface                 * pUnoI,
125     typelib_TypeDescription const * pMemberType,
126     void                          * pReturn,
127     void                          * pArgs[],
128     uno_Any                      ** ppException)
129     SAL_THROW_EXTERN_C()
130 {
131     Proxy * pThis = static_cast<Proxy *>(pUnoI);
132 
133     typelib_MethodParameter            param;
134     sal_Int32                          nParams = 0;
135     typelib_MethodParameter          * pParams = 0;
136     typelib_TypeDescriptionReference * pReturnTypeRef = 0;
137     // sal_Int32                          nOutParams = 0;
138 
139     switch (pMemberType->eTypeClass)
140     {
141     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
142         if (pReturn)
143         {
144             pReturnTypeRef =
145                 ((typelib_InterfaceAttributeTypeDescription *)
146                  pMemberType)->pAttributeTypeRef;
147             nParams = 0;
148             pParams = NULL;
149         }
150         else
151         {
152             param.pTypeRef = ((typelib_InterfaceAttributeTypeDescription *)
153                               pMemberType)->pAttributeTypeRef;
154             param.bIn = sal_True;
155             param.bOut = sal_False;
156             nParams = 1;
157             pParams = &param;
158         }
159         break;
160     case typelib_TypeClass_INTERFACE_METHOD:
161     {
162         typelib_InterfaceMethodTypeDescription * method_td =
163             (typelib_InterfaceMethodTypeDescription *) pMemberType;
164         pReturnTypeRef = method_td->pReturnTypeRef;
165         nParams = method_td->nParams;
166         pParams = method_td->pParams;
167         break;
168     }
169     default:
170         OSL_ENSURE( sal_False, "### illegal member typeclass!" );
171         abort();
172     }
173 
174     pThis->dispatch( pReturnTypeRef,
175                      pParams,
176                      nParams,
177                      pMemberType,
178                      pReturn,
179                      pArgs,
180                      ppException );
181 }}
182 
Proxy_free(uno_ExtEnvironment *,void * pProxy)183 extern "C" void SAL_CALL Proxy_free(uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
184 {
185     Proxy * pThis = static_cast<Proxy * >(reinterpret_cast<uno_Interface *>(pProxy));
186     delete pThis;
187 }
188 
189 extern "C" {
s_Proxy_acquire(uno_Interface * pUnoI)190 static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
191 {
192     Proxy * pProxy = static_cast<Proxy *>(pUnoI);
193     pProxy->acquire();
194 }
195 
s_Proxy_release(uno_Interface * pUnoI)196 static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
197 {
198     Proxy * pProxy = static_cast<Proxy *>(pUnoI);
199     pProxy->release();
200 }
201 
s_acquireAndRegister_v(va_list * pParam)202 static void s_acquireAndRegister_v(va_list * pParam)
203 {
204     uno_Interface                    * pUnoI      = va_arg(*pParam, uno_Interface *);
205     rtl_uString                      * pOid       = va_arg(*pParam, rtl_uString *);
206     typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
207     uno_ExtEnvironment               * pEnv       = va_arg(*pParam, uno_ExtEnvironment *);
208 
209     pUnoI->acquire(pUnoI);
210     pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
211 }
212 }
213 
Proxy(uno::Mapping const & to_from,uno_Environment * pTo,uno_Environment * pFrom,uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTypeDescr,rtl::OUString const & rOId,cppu::helper::purpenv::ProbeFun * probeFun,void * pProbeContext)214 Proxy::Proxy(uno::Mapping                  const & to_from,
215              uno_Environment                     * pTo,
216              uno_Environment                     * pFrom,
217              uno_Interface                       * pUnoI,
218              typelib_InterfaceTypeDescription    * pTypeDescr,
219              rtl::OUString                 const & rOId,
220              cppu::helper::purpenv::ProbeFun     * probeFun,
221              void                                * pProbeContext
222 )
223     SAL_THROW(())
224         : m_nRef         (1),
225           m_from         (pFrom),
226           m_to           (pTo),
227           m_from_to      (pFrom, pTo),
228           m_to_from      (to_from),
229           m_pUnoI        (pUnoI),
230           m_pTypeDescr   (pTypeDescr),
231           m_aOId         (rOId),
232           m_probeFun     (probeFun),
233           m_pProbeContext(pProbeContext)
234 {
235     LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
236 
237     typelib_typedescription_acquire((typelib_TypeDescription *)m_pTypeDescr);
238     if (!((typelib_TypeDescription *)m_pTypeDescr)->bComplete)
239         typelib_typedescription_complete((typelib_TypeDescription **)&m_pTypeDescr);
240 
241     OSL_ENSURE(((typelib_TypeDescription *)m_pTypeDescr)->bComplete, "### type is incomplete!");
242 
243     uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
244 
245     // uno_Interface
246     uno_Interface::acquire     = s_Proxy_acquire;
247     uno_Interface::release     = s_Proxy_release;
248     uno_Interface::pDispatcher = s_Proxy_dispatch;
249 }
250 
s_releaseAndRevoke_v(va_list * pParam)251 extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
252 {
253     uno_ExtEnvironment * pEnv  = va_arg(*pParam, uno_ExtEnvironment *);
254     uno_Interface      * pUnoI = va_arg(*pParam, uno_Interface *);
255 
256     pEnv->revokeInterface(pEnv, reinterpret_cast<void *>(pUnoI));
257     pUnoI->release(pUnoI);
258 }}
259 
~Proxy()260 Proxy::~Proxy()
261 {
262     LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
263 
264     uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
265 
266     typelib_typedescription_release((typelib_TypeDescription *)m_pTypeDescr);
267 }
268 
getAcquireMethod(void)269 static uno::TypeDescription getAcquireMethod(void)
270 {
271     typelib_TypeDescriptionReference * type_XInterface =
272         * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
273 
274     typelib_TypeDescription * pTXInterfaceDescr = 0;
275     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
276     uno::TypeDescription acquire(
277         reinterpret_cast< typelib_InterfaceTypeDescription * >(
278             pTXInterfaceDescr)->ppAllMembers[1]);
279     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
280 
281     return acquire;
282 }
283 
getReleaseMethod(void)284 static uno::TypeDescription getReleaseMethod(void)
285 {
286     typelib_TypeDescriptionReference * type_XInterface =
287         * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
288 
289     typelib_TypeDescription * pTXInterfaceDescr = 0;
290     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
291     uno::TypeDescription release(
292         reinterpret_cast< typelib_InterfaceTypeDescription * >(
293             pTXInterfaceDescr)->ppAllMembers[2]);
294     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
295 
296     return release;
297 }
298 
299 static uno::TypeDescription s_acquireMethod(getAcquireMethod());
300 static uno::TypeDescription s_releaseMethod(getReleaseMethod());
301 
acquire(void)302 void Proxy::acquire(void)
303 {
304     if (m_probeFun)
305         m_probeFun(true,
306                    this,
307                    m_pProbeContext,
308                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
309                    NULL,
310                    0,
311                    s_acquireMethod.get(),
312                    NULL,
313                    NULL,
314                    NULL);
315 
316     if (osl_incrementInterlockedCount(&m_nRef) == 1)
317     {
318         // rebirth of proxy zombie
319         void * pThis = this;
320         m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
321                                                       &pThis,
322                                                       Proxy_free,
323                                                       m_aOId.pData,
324                                                       m_pTypeDescr);
325         OSL_ASSERT(pThis == this);
326     }
327 
328     if (m_probeFun)
329         m_probeFun(false,
330                    this,
331                    m_pProbeContext,
332                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
333                    NULL,
334                    0,
335                    s_acquireMethod.get(),
336                    NULL,
337                    NULL,
338                    NULL);
339 
340 }
341 
release(void)342 void Proxy::release(void)
343 {
344     cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
345     void                            * pProbeContext = m_pProbeContext;
346 
347     if (m_probeFun)
348         m_probeFun(true,
349                    this,
350                    m_pProbeContext,
351                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
352                    NULL,
353                    0,
354                    s_releaseMethod.get(),
355                    NULL,
356                    NULL,
357                    NULL);
358 
359     if (osl_decrementInterlockedCount(&m_nRef) == 0)
360         m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
361 
362     if (probeFun)
363         probeFun(false,
364                  this,
365                  pProbeContext,
366                  *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
367                  NULL,
368                  0,
369                  s_releaseMethod.get(),
370                  NULL,
371                  NULL,
372                  NULL);
373 
374 }
375 
376 
377 extern "C" {
s_type_destructData_v(va_list * pParam)378 static void s_type_destructData_v(va_list * pParam)
379 {
380     void * ret = va_arg(*pParam, void *);
381     typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
382 
383     uno_type_destructData(ret, pReturnTypeRef, 0);
384 }
385 
s_dispatcher_v(va_list * pParam)386 static void s_dispatcher_v(va_list * pParam)
387 {
388     uno_Interface                 * pUnoI       = va_arg(*pParam, uno_Interface *);
389     typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
390     void                          * pReturn     = va_arg(*pParam, void *);
391     void                         ** pArgs       = va_arg(*pParam, void **);
392     uno_Any                      ** ppException = va_arg(*pParam, uno_Any **);
393 
394     pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
395 }
396 }
397 
dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,typelib_MethodParameter * pParams,sal_Int32 nParams,typelib_TypeDescription const * pMemberType,void * pReturn,void * pArgs[],uno_Any ** ppException)398 void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
399                      typelib_MethodParameter          * pParams,
400                      sal_Int32                          nParams,
401                      typelib_TypeDescription    const * pMemberType,
402                      void                             * pReturn,
403                      void                             * pArgs[],
404                      uno_Any                         ** ppException)
405 {
406     if (m_probeFun)
407         m_probeFun(true,
408                    this,
409                    m_pProbeContext,
410                    pReturnTypeRef,
411                    pParams,
412                    nParams,
413                    pMemberType,
414                    pReturn,
415                    pArgs,
416                    ppException);
417 
418     void ** args = (void **) alloca( sizeof (void *) * nParams );
419 
420     typelib_TypeDescription * return_td = 0;
421     void * ret = pReturn;
422     if (pReturnTypeRef)
423     {
424         TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
425 
426         if (relatesToInterface(return_td))
427             ret = alloca(return_td->nSize);
428 
429         TYPELIB_DANGER_RELEASE(return_td);
430     }
431 
432     for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
433     {
434         typelib_MethodParameter const & param = pParams[nPos];
435         typelib_TypeDescription * td = 0;
436         TYPELIB_DANGER_GET( &td, param.pTypeRef );
437         if (relatesToInterface(td))
438         {
439             args[nPos] = alloca(td->nSize);
440             if (param.bIn)
441             {
442                 uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
443             }
444         }
445         else
446         {
447             args[nPos] = pArgs[nPos];
448         }
449         TYPELIB_DANGER_RELEASE( td );
450     }
451 
452     uno_Any exc_data;
453     uno_Any * exc = &exc_data;
454 
455     // do the UNO call...
456     uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
457 
458     if (exc == 0)
459     {
460         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
461         {
462             if (args[nPos] != pArgs[nPos])
463             {
464                 typelib_MethodParameter const & param = pParams[nPos];
465                 if (param.bOut)
466                 {
467                     if (param.bIn) // is inout
468                     {
469                         uno_type_destructData(pArgs[nPos], param.pTypeRef, 0);
470                     }
471                     uno_type_copyAndConvertData(pArgs[ nPos ],
472                                                 args[ nPos ],
473                                                 param.pTypeRef,
474                                                 m_to_from.get());
475                 }
476                 uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
477             }
478         }
479         if (ret != pReturn)
480         {
481             uno_type_copyAndConvertData(pReturn,
482                                         ret,
483                                         pReturnTypeRef,
484                                         m_to_from.get());
485 
486             uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
487         }
488 
489         *ppException = 0;
490     }
491     else // exception occured
492     {
493         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
494         {
495             if (args[nPos] != pArgs[nPos])
496             {
497                 typelib_MethodParameter const & param = pParams[nPos];
498                 if (param.bIn)
499                 {
500                     uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
501                 }
502             }
503         }
504 
505         uno_type_any_constructAndConvert(*ppException,
506                                          exc->pData,
507                                          exc->pType,
508                                          m_to_from.get());
509 
510         // FIXME: need to destruct in m_to
511         uno_any_destruct(exc, 0);
512     }
513 
514     if (m_probeFun)
515         m_probeFun(false,
516                    this,
517                    m_pProbeContext,
518                    pReturnTypeRef,
519                    pParams,
520                    nParams,
521                    pMemberType,
522                    pReturn,
523                    pArgs,
524                    ppException);
525 }
526 
527