Branch libreoffice-5-0-4
[LibreOffice.git] / cppu / source / helper / purpenv / helper_purpenv_Proxy.cxx
blob90ee6b052a6f5ebdbe5af99d44176f3ea8458256
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "Proxy.hxx"
23 #include "sal/alloca.h"
24 #include "uno/dispatcher.h"
25 #include "typelib/typedescription.hxx"
26 #include "cppu/EnvDcp.hxx"
29 //#define LOG_LIFECYCLE_Proxy
30 #ifdef LOG_LIFECYCLE_Proxy
31 # include <iostream>
32 # define LOG_LIFECYCLE_Proxy_emit(x) x
34 #else
35 # define LOG_LIFECYCLE_Proxy_emit(x)
37 #endif
40 using namespace com::sun::star;
43 static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
45 switch (pTypeDescr->eTypeClass)
47 // case typelib_TypeClass_TYPEDEF:
48 case typelib_TypeClass_SEQUENCE:
50 switch (reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType->eTypeClass)
52 case typelib_TypeClass_INTERFACE:
53 case typelib_TypeClass_ANY: // might relate to interface
54 return true;
55 case typelib_TypeClass_SEQUENCE:
56 case typelib_TypeClass_STRUCT:
57 case typelib_TypeClass_EXCEPTION:
59 typelib_TypeDescription * pTD = 0;
60 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType );
61 bool bRel = relatesToInterface( pTD );
62 TYPELIB_DANGER_RELEASE( pTD );
63 return bRel;
65 default:
68 return false;
70 case typelib_TypeClass_STRUCT:
71 case typelib_TypeClass_EXCEPTION:
73 // ...optimized... to avoid getDescription() calls!
74 typelib_CompoundTypeDescription * pComp = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr);
75 typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
76 for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
78 switch (pTypes[nPos]->eTypeClass)
80 case typelib_TypeClass_INTERFACE:
81 case typelib_TypeClass_ANY: // might relate to interface
82 return true;
83 // case typelib_TypeClass_TYPEDEF:
84 case typelib_TypeClass_SEQUENCE:
85 case typelib_TypeClass_STRUCT:
86 case typelib_TypeClass_EXCEPTION:
88 typelib_TypeDescription * pTD = 0;
89 TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
90 bool bRel = relatesToInterface( pTD );
91 TYPELIB_DANGER_RELEASE( pTD );
92 if (bRel)
93 return true;
95 default:
99 if (pComp->pBaseTypeDescription)
100 return relatesToInterface( &pComp->pBaseTypeDescription->aBase );
101 break;
103 case typelib_TypeClass_ANY: // might relate to interface
104 case typelib_TypeClass_INTERFACE:
105 return true;
107 default:
110 return false;
113 extern "C" { static void SAL_CALL s_Proxy_dispatch(
114 uno_Interface * pUnoI,
115 typelib_TypeDescription const * pMemberType,
116 void * pReturn,
117 void * pArgs[],
118 uno_Any ** ppException)
119 SAL_THROW_EXTERN_C()
121 Proxy * pThis = static_cast<Proxy *>(pUnoI);
123 typelib_MethodParameter param;
124 sal_Int32 nParams = 0;
125 typelib_MethodParameter * pParams = 0;
126 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
127 // sal_Int32 nOutParams = 0;
129 switch (pMemberType->eTypeClass)
131 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
132 if (pReturn)
134 pReturnTypeRef =
135 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
136 pMemberType)->pAttributeTypeRef;
137 nParams = 0;
138 pParams = NULL;
140 else
142 param.pTypeRef = reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
143 pMemberType)->pAttributeTypeRef;
144 param.bIn = sal_True;
145 param.bOut = sal_False;
146 nParams = 1;
147 pParams = &param;
149 break;
150 case typelib_TypeClass_INTERFACE_METHOD:
152 typelib_InterfaceMethodTypeDescription const * method_td =
153 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType);
154 pReturnTypeRef = method_td->pReturnTypeRef;
155 nParams = method_td->nParams;
156 pParams = method_td->pParams;
157 break;
159 default:
160 OSL_FAIL( "### illegal member typeclass!" );
161 abort();
164 pThis->dispatch( pReturnTypeRef,
165 pParams,
166 nParams,
167 pMemberType,
168 pReturn,
169 pArgs,
170 ppException );
173 extern "C" void SAL_CALL Proxy_free(SAL_UNUSED_PARAMETER uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
175 Proxy * pThis = static_cast<Proxy * >(static_cast<uno_Interface *>(pProxy));
176 delete pThis;
179 extern "C" {
180 static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
182 Proxy * pProxy = static_cast<Proxy *>(pUnoI);
183 pProxy->acquire();
186 static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
188 Proxy * pProxy = static_cast<Proxy *>(pUnoI);
189 pProxy->release();
192 static void s_acquireAndRegister_v(va_list * pParam)
194 uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
195 rtl_uString * pOid = va_arg(*pParam, rtl_uString *);
196 typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
197 uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
199 pUnoI->acquire(pUnoI);
200 pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
204 Proxy::Proxy(uno::Mapping const & to_from,
205 uno_Environment * pTo,
206 uno_Environment * pFrom,
207 uno_Interface * pUnoI,
208 typelib_InterfaceTypeDescription * pTypeDescr,
209 rtl::OUString const & rOId,
210 cppu::helper::purpenv::ProbeFun * probeFun,
211 void * pProbeContext
213 : m_nRef (1),
214 m_from (pFrom),
215 m_to (pTo),
216 m_from_to (pFrom, pTo),
217 m_to_from (to_from),
218 m_pUnoI (pUnoI),
219 m_pTypeDescr (pTypeDescr),
220 m_aOId (rOId),
221 m_probeFun (probeFun),
222 m_pProbeContext(pProbeContext)
224 LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
226 typelib_typedescription_acquire(&m_pTypeDescr->aBase);
227 if (!m_pTypeDescr->aBase.bComplete)
228 typelib_typedescription_complete(reinterpret_cast<typelib_TypeDescription **>(&m_pTypeDescr));
230 OSL_ENSURE(m_pTypeDescr->aBase.bComplete, "### type is incomplete!");
232 uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
234 // uno_Interface
235 uno_Interface::acquire = s_Proxy_acquire;
236 uno_Interface::release = s_Proxy_release;
237 uno_Interface::pDispatcher = s_Proxy_dispatch;
240 extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
242 uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
243 uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
245 pEnv->revokeInterface(pEnv, pUnoI);
246 pUnoI->release(pUnoI);
249 Proxy::~Proxy()
251 LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
253 uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
255 typelib_typedescription_release(&m_pTypeDescr->aBase);
258 static uno::TypeDescription getAcquireMethod()
260 typelib_TypeDescriptionReference * type_XInterface =
261 * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
263 typelib_TypeDescription * pTXInterfaceDescr = 0;
264 TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
265 uno::TypeDescription acquire(
266 reinterpret_cast< typelib_InterfaceTypeDescription * >(
267 pTXInterfaceDescr)->ppAllMembers[1]);
268 TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
270 return acquire;
273 static uno::TypeDescription getReleaseMethod()
275 typelib_TypeDescriptionReference * type_XInterface =
276 * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
278 typelib_TypeDescription * pTXInterfaceDescr = 0;
279 TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
280 uno::TypeDescription release(
281 reinterpret_cast< typelib_InterfaceTypeDescription * >(
282 pTXInterfaceDescr)->ppAllMembers[2]);
283 TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
285 return release;
288 static uno::TypeDescription s_acquireMethod(getAcquireMethod());
289 static uno::TypeDescription s_releaseMethod(getReleaseMethod());
291 void Proxy::acquire()
293 if (m_probeFun)
294 m_probeFun(true,
295 this,
296 m_pProbeContext,
297 *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
298 NULL,
300 s_acquireMethod.get(),
301 NULL,
302 NULL,
303 NULL);
305 if (osl_atomic_increment(&m_nRef) == 1)
307 // rebirth of proxy zombie
308 void * pThis = this;
309 m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
310 &pThis,
311 Proxy_free,
312 m_aOId.pData,
313 m_pTypeDescr);
314 OSL_ASSERT(pThis == this);
317 if (m_probeFun)
318 m_probeFun(false,
319 this,
320 m_pProbeContext,
321 *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
322 NULL,
324 s_acquireMethod.get(),
325 NULL,
326 NULL,
327 NULL);
331 void Proxy::release()
333 cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
334 void * pProbeContext = m_pProbeContext;
336 if (m_probeFun)
337 m_probeFun(true,
338 this,
339 m_pProbeContext,
340 *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
341 NULL,
343 s_releaseMethod.get(),
344 NULL,
345 NULL,
346 NULL);
348 if (osl_atomic_decrement(&m_nRef) == 0)
349 m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
351 if (probeFun)
352 probeFun(false,
353 this,
354 pProbeContext,
355 *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
356 NULL,
358 s_releaseMethod.get(),
359 NULL,
360 NULL,
361 NULL);
366 extern "C" {
367 static void s_type_destructData_v(va_list * pParam)
369 void * ret = va_arg(*pParam, void *);
370 typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
372 uno_type_destructData(ret, pReturnTypeRef, 0);
375 static void s_dispatcher_v(va_list * pParam)
377 uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
378 typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
379 void * pReturn = va_arg(*pParam, void *);
380 void ** pArgs = va_arg(*pParam, void **);
381 uno_Any ** ppException = va_arg(*pParam, uno_Any **);
383 pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
387 void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
388 typelib_MethodParameter * pParams,
389 sal_Int32 nParams,
390 typelib_TypeDescription const * pMemberType,
391 void * pReturn,
392 void * pArgs[],
393 uno_Any ** ppException)
395 if (m_probeFun)
396 m_probeFun(true,
397 this,
398 m_pProbeContext,
399 pReturnTypeRef,
400 pParams,
401 nParams,
402 pMemberType,
403 pReturn,
404 pArgs,
405 ppException);
407 void ** args = static_cast<void **>(alloca( sizeof (void *) * nParams ));
409 typelib_TypeDescription * return_td = 0;
410 void * ret = pReturn;
411 if (pReturnTypeRef)
413 TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
415 if (relatesToInterface(return_td))
416 ret = alloca(return_td->nSize);
418 TYPELIB_DANGER_RELEASE(return_td);
421 for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
423 typelib_MethodParameter const & param = pParams[nPos];
424 typelib_TypeDescription * td = 0;
425 TYPELIB_DANGER_GET( &td, param.pTypeRef );
426 if (relatesToInterface(td))
428 args[nPos] = alloca(td->nSize);
429 if (param.bIn)
431 uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
434 else
436 args[nPos] = pArgs[nPos];
438 TYPELIB_DANGER_RELEASE( td );
441 uno_Any exc_data;
442 uno_Any * exc = &exc_data;
444 // do the UNO call...
445 uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
447 if (exc == 0)
449 for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
451 if (args[nPos] != pArgs[nPos])
453 typelib_MethodParameter const & param = pParams[nPos];
454 if (param.bOut)
456 if (param.bIn) // is inout
458 uno_type_destructData(pArgs[nPos], param.pTypeRef, 0);
460 uno_type_copyAndConvertData(pArgs[ nPos ],
461 args[ nPos ],
462 param.pTypeRef,
463 m_to_from.get());
465 uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
468 if (ret != pReturn)
470 uno_type_copyAndConvertData(pReturn,
471 ret,
472 pReturnTypeRef,
473 m_to_from.get());
475 uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
478 *ppException = 0;
480 else // exception occurred
482 for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
484 if (args[nPos] != pArgs[nPos])
486 typelib_MethodParameter const & param = pParams[nPos];
487 if (param.bIn)
489 uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
494 uno_type_any_constructAndConvert(*ppException,
495 exc->pData,
496 exc->pType,
497 m_to_from.get());
499 // FIXME: need to destruct in m_to
500 uno_any_destruct(exc, 0);
503 if (m_probeFun)
504 m_probeFun(false,
505 this,
506 m_pProbeContext,
507 pReturnTypeRef,
508 pParams,
509 nParams,
510 pMemberType,
511 pReturn,
512 pArgs,
513 ppException);
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */