1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <osl/diagnose.h>
22 #include <osl/interlck.h>
23 #include <osl/doublecheckedlocking.h>
24 #include <osl/mutex.hxx>
25 #include <rtl/ref.hxx>
26 #include <uno/dispatcher.hxx>
28 #include <uno/lbnames.h>
29 #include <uno/mapping.hxx>
30 #include <uno/environment.hxx>
31 #include <typelib/typedescription.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <cppuhelper/implementationentry.hxx>
35 #include <cppuhelper/factory.hxx>
36 #include <cppuhelper/supportsservice.hxx>
37 #include <com/sun/star/lang/XServiceInfo.hpp>
38 #include <com/sun/star/registry/XRegistryKey.hpp>
39 #include <com/sun/star/reflection/XProxyFactory.hpp>
40 #include <com/sun/star/uno/RuntimeException.hpp>
42 #define SERVICE_NAME "com.sun.star.reflection.ProxyFactory"
43 #define IMPL_NAME "com.sun.star.comp.reflection.ProxyFactory"
46 using namespace ::com::sun::star
;
47 using namespace css::uno
;
53 OUString
proxyfac_getImplementationName()
55 return OUString(IMPL_NAME
);
58 Sequence
< OUString
> proxyfac_getSupportedServiceNames()
60 OUString str_name
= SERVICE_NAME
;
61 return Sequence
< OUString
>( &str_name
, 1 );
65 struct FactoryImpl
: public ::cppu::WeakImplHelper
< lang::XServiceInfo
,
66 reflection::XProxyFactory
>
68 Environment m_uno_env
;
69 Environment m_cpp_env
;
73 UnoInterfaceReference
binuno_queryInterface(
74 UnoInterfaceReference
const & unoI
,
75 typelib_InterfaceTypeDescription
* pTypeDescr
);
80 virtual OUString SAL_CALL
getImplementationName() override
;
81 virtual sal_Bool SAL_CALL
supportsService( const OUString
& rServiceName
) override
;
82 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
85 virtual Reference
< XAggregation
> SAL_CALL
createProxy(
86 Reference
< XInterface
> const & xTarget
) override
;
90 UnoInterfaceReference
FactoryImpl::binuno_queryInterface(
91 UnoInterfaceReference
const & unoI
,
92 typelib_InterfaceTypeDescription
* pTypeDescr
)
94 // init queryInterface() td
95 static typelib_TypeDescription
* s_pQITD
= nullptr;
96 if (s_pQITD
== nullptr)
98 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
99 if (s_pQITD
== nullptr)
101 typelib_TypeDescription
* pTXInterfaceDescr
= nullptr;
104 cppu::UnoType
<XInterface
>::get().getTypeLibType() );
105 typelib_TypeDescription
* pQITD
= nullptr;
106 typelib_typedescriptionreference_getDescription(
107 &pQITD
, reinterpret_cast< typelib_InterfaceTypeDescription
* >(
108 pTXInterfaceDescr
)->ppAllMembers
[ 0 ] );
109 TYPELIB_DANGER_RELEASE( pTXInterfaceDescr
);
110 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
116 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
120 args
[ 0 ] = &reinterpret_cast< typelib_TypeDescription
* >(
121 pTypeDescr
)->pWeakRef
;
122 uno_Any ret_val
, exc_space
;
123 uno_Any
* exc
= &exc_space
;
125 unoI
.dispatch( s_pQITD
, &ret_val
, args
, &exc
);
129 UnoInterfaceReference ret
;
130 if (ret_val
.pType
->eTypeClass
== typelib_TypeClass_INTERFACE
)
132 ret
.set( *static_cast< uno_Interface
** >(ret_val
.pData
),
134 typelib_typedescriptionreference_release( ret_val
.pType
);
138 uno_any_destruct( &ret_val
, nullptr );
144 // exception occurred:
146 typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType
<RuntimeException
>::get().getTypeLibType(),
148 "### RuntimeException expected!" );
150 uno_type_copyAndConvertData(
151 &cpp_exc
, exc
, cppu::UnoType
<decltype(cpp_exc
)>::get().getTypeLibType(),
153 uno_any_destruct( exc
, nullptr );
154 ::cppu::throwException( cpp_exc
);
155 OSL_ASSERT( false ); // way of no return
156 return UnoInterfaceReference(); // for dummy
161 struct ProxyRoot
: public ::cppu::OWeakAggObject
164 virtual Any SAL_CALL
queryAggregation( Type
const & rType
) override
;
166 inline ProxyRoot( ::rtl::Reference
< FactoryImpl
> const & factory
,
167 Reference
< XInterface
> const & xTarget
);
169 ::rtl::Reference
< FactoryImpl
> m_factory
;
172 UnoInterfaceReference m_target
;
176 struct binuno_Proxy
: public uno_Interface
178 oslInterlockedCount m_nRefCount
;
179 ::rtl::Reference
< ProxyRoot
> m_root
;
180 UnoInterfaceReference m_target
;
182 TypeDescription m_typeDescr
;
185 ::rtl::Reference
< ProxyRoot
> const & root
,
186 UnoInterfaceReference
const & target
,
187 OUString
const & oid
, TypeDescription
const & typeDescr
);
194 static void binuno_proxy_free(
195 uno_ExtEnvironment
* pEnv
, void * pProxy
)
197 binuno_Proxy
* proxy
= static_cast< binuno_Proxy
* >(
198 static_cast< uno_Interface
* >( pProxy
) );
199 OSL_ASSERT( proxy
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
== pEnv
);
204 static void binuno_proxy_acquire( uno_Interface
* pUnoI
)
206 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
207 if (osl_atomic_increment( &that
->m_nRefCount
) == 1)
210 uno_ExtEnvironment
* uno_env
=
211 that
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
;
212 OSL_ASSERT( uno_env
!= nullptr );
213 (*uno_env
->registerProxyInterface
)(
214 uno_env
, reinterpret_cast< void ** >( &pUnoI
), binuno_proxy_free
,
216 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
217 that
->m_typeDescr
.get() ) );
218 OSL_ASSERT( that
== static_cast< binuno_Proxy
* >( pUnoI
) );
223 static void binuno_proxy_release( uno_Interface
* pUnoI
)
225 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
226 if (osl_atomic_decrement( &that
->m_nRefCount
) == 0)
228 uno_ExtEnvironment
* uno_env
=
229 that
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
;
230 OSL_ASSERT( uno_env
!= nullptr );
231 (*uno_env
->revokeInterface
)( uno_env
, pUnoI
);
236 static void binuno_proxy_dispatch(
237 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberType
,
238 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
240 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
241 switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription
const * >(
242 pMemberType
)->nPosition
)
244 case 0: // queryInterface()
249 *static_cast< Type
const * >( pArgs
[ 0 ] );
250 Any
ret( that
->m_root
->queryInterface( rType
) );
251 uno_type_copyAndConvertData(
252 pReturn
, &ret
, cppu::UnoType
<decltype(ret
)>::get().getTypeLibType(),
253 that
->m_root
->m_factory
->m_cpp2uno
.get() );
254 *ppException
= nullptr; // no exc
256 catch (RuntimeException
&)
258 Any
exc( ::cppu::getCaughtException() );
259 uno_type_any_constructAndConvert(
260 *ppException
, const_cast< void * >(exc
.getValue()),
261 exc
.getValueTypeRef(),
262 that
->m_root
->m_factory
->m_cpp2uno
.get() );
267 binuno_proxy_acquire( pUnoI
);
268 *ppException
= nullptr; // no exc
271 binuno_proxy_release( pUnoI
);
272 *ppException
= nullptr; // no exc
275 that
->m_target
.dispatch( pMemberType
, pReturn
, pArgs
, ppException
);
283 inline binuno_Proxy::binuno_Proxy(
284 ::rtl::Reference
< ProxyRoot
> const & root
,
285 UnoInterfaceReference
const & target
,
286 OUString
const & oid
, TypeDescription
const & typeDescr
)
291 m_typeDescr( typeDescr
)
293 uno_Interface::acquire
= binuno_proxy_acquire
;
294 uno_Interface::release
= binuno_proxy_release
;
295 uno_Interface::pDispatcher
= binuno_proxy_dispatch
;
298 inline ProxyRoot::ProxyRoot(
299 ::rtl::Reference
< FactoryImpl
> const & factory
,
300 Reference
< XInterface
> const & xTarget
)
301 : m_factory( factory
)
303 m_factory
->m_cpp2uno
.mapInterface(
304 reinterpret_cast< void ** >( &m_target
.m_pUnoI
), xTarget
.get(),
305 cppu::UnoType
<decltype(xTarget
)>::get() );
306 OSL_ENSURE( m_target
.is(), "### mapping interface failed!" );
310 Any
ProxyRoot::queryAggregation( Type
const & rType
)
312 Any
ret( OWeakAggObject::queryAggregation( rType
) );
313 if (! ret
.hasValue())
315 typelib_TypeDescription
* pTypeDescr
= nullptr;
316 TYPELIB_DANGER_GET( &pTypeDescr
, rType
.getTypeLibType() );
319 Reference
< XInterface
> xProxy
;
320 uno_ExtEnvironment
* cpp_env
= m_factory
->m_cpp_env
.get()->pExtEnv
;
321 OSL_ASSERT( cpp_env
!= nullptr );
323 // mind a new delegator, calculate current root:
324 Reference
< XInterface
> xRoot(
325 static_cast< OWeakObject
* >(this), UNO_QUERY_THROW
);
327 (*cpp_env
->getObjectIdentifier
)( cpp_env
, &oid
.pData
, xRoot
.get() );
328 OSL_ASSERT( !oid
.isEmpty() );
330 (*cpp_env
->getRegisteredInterface
)(
331 cpp_env
, reinterpret_cast< void ** >( &xProxy
),
332 oid
.pData
, reinterpret_cast<
333 typelib_InterfaceTypeDescription
* >(pTypeDescr
) );
336 // perform query on target:
337 UnoInterfaceReference
proxy_target(
338 m_factory
->binuno_queryInterface(
339 m_target
, reinterpret_cast<
340 typelib_InterfaceTypeDescription
* >(pTypeDescr
) ) );
341 if (proxy_target
.is())
343 // ensure root's object entries:
344 UnoInterfaceReference root
;
345 m_factory
->m_cpp2uno
.mapInterface(
346 reinterpret_cast< void ** >( &root
.m_pUnoI
),
347 xRoot
.get(), cppu::UnoType
<decltype(xRoot
)>::get() );
349 UnoInterfaceReference
proxy(
350 // ref count initially 1:
351 new binuno_Proxy( this, proxy_target
, oid
, pTypeDescr
),
353 uno_ExtEnvironment
* uno_env
=
354 m_factory
->m_uno_env
.get()->pExtEnv
;
355 OSL_ASSERT( uno_env
!= nullptr );
356 (*uno_env
->registerProxyInterface
)(
357 uno_env
, reinterpret_cast< void ** >( &proxy
.m_pUnoI
),
358 binuno_proxy_free
, oid
.pData
,
359 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
362 m_factory
->m_uno2cpp
.mapInterface(
363 reinterpret_cast< void ** >( &xProxy
),
364 proxy
.get(), pTypeDescr
);
368 ret
.setValue( &xProxy
, pTypeDescr
);
370 catch (...) // finally
372 TYPELIB_DANGER_RELEASE( pTypeDescr
);
375 TYPELIB_DANGER_RELEASE( pTypeDescr
);
381 FactoryImpl::FactoryImpl()
383 OUString uno
= UNO_LB_UNO
;
384 OUString cpp
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
387 reinterpret_cast< uno_Environment
** >( &m_uno_env
), uno
.pData
, nullptr );
388 OSL_ENSURE( m_uno_env
.is(), "### cannot get binary uno env!" );
391 reinterpret_cast< uno_Environment
** >( &m_cpp_env
), cpp
.pData
, nullptr );
392 OSL_ENSURE( m_cpp_env
.is(), "### cannot get C++ uno env!" );
395 reinterpret_cast< uno_Mapping
** >( &m_uno2cpp
),
396 m_uno_env
.get(), m_cpp_env
.get(), nullptr );
397 OSL_ENSURE( m_uno2cpp
.is(), "### cannot get bridge uno <-> C++!" );
400 reinterpret_cast< uno_Mapping
** >( &m_cpp2uno
),
401 m_cpp_env
.get(), m_uno_env
.get(), nullptr );
402 OSL_ENSURE( m_cpp2uno
.is(), "### cannot get bridge C++ <-> uno!" );
407 Reference
< XAggregation
> FactoryImpl::createProxy(
408 Reference
< XInterface
> const & xTarget
)
410 return new ProxyRoot( this, xTarget
);
415 OUString
FactoryImpl::getImplementationName()
417 return proxyfac_getImplementationName();
420 sal_Bool
FactoryImpl::supportsService( const OUString
& rServiceName
)
422 return cppu::supportsService(this, rServiceName
);
425 Sequence
< OUString
> FactoryImpl::getSupportedServiceNames()
427 return proxyfac_getSupportedServiceNames();
430 /// @throws Exception
431 Reference
< XInterface
> proxyfac_create(
432 SAL_UNUSED_PARAMETER Reference
< XComponentContext
> const & )
434 Reference
< XInterface
> xRet
;
435 static osl::Mutex s_mutex
;
436 // note: don't use ::osl::Mutex::getGlobalMutex() here, it deadlocks
437 // with getImplHelperInitMutex()
438 ::osl::MutexGuard
guard(s_mutex
);
439 static WeakReference
< XInterface
> rwInstance
;
444 xRet
= static_cast< ::cppu::OWeakObject
* >(new FactoryImpl
);
450 static const ::cppu::ImplementationEntry g_entries
[] =
453 proxyfac_create
, proxyfac_getImplementationName
,
454 proxyfac_getSupportedServiceNames
, ::cppu::createSingleComponentFactory
,
457 { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
462 extern "C" SAL_DLLPUBLIC_EXPORT
void * proxyfac_component_getFactory(
463 const sal_Char
* pImplName
, void * pServiceManager
, void * pRegistryKey
)
465 return ::cppu::component_getFactoryHelper(
466 pImplName
, pServiceManager
, pRegistryKey
, g_entries
);
469 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */