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 <rtl/ref.hxx>
24 #include <uno/dispatcher.hxx>
26 #include <uno/lbnames.h>
27 #include <uno/mapping.hxx>
28 #include <uno/environment.hxx>
29 #include <typelib/typedescription.hxx>
30 #include <cppuhelper/exc_hlp.hxx>
31 #include <cppuhelper/implbase.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <cppuhelper/weak.hxx>
34 #include <cppuhelper/weakagg.hxx>
35 #include <com/sun/star/lang/XServiceInfo.hpp>
36 #include <com/sun/star/reflection/XProxyFactory.hpp>
37 #include <com/sun/star/uno/RuntimeException.hpp>
38 #include <com/sun/star/uno/XComponentContext.hpp>
42 using namespace ::com::sun::star
;
43 using namespace css::uno
;
49 struct FactoryImpl
: public ::cppu::WeakImplHelper
< lang::XServiceInfo
,
50 reflection::XProxyFactory
>
52 Environment m_uno_env
;
53 Environment m_cpp_env
;
57 UnoInterfaceReference
binuno_queryInterface(
58 UnoInterfaceReference
const & unoI
,
59 typelib_InterfaceTypeDescription
* pTypeDescr
);
64 virtual OUString SAL_CALL
getImplementationName() override
;
65 virtual sal_Bool SAL_CALL
supportsService( const OUString
& rServiceName
) override
;
66 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
69 virtual Reference
< XAggregation
> SAL_CALL
createProxy(
70 Reference
< XInterface
> const & xTarget
) override
;
74 UnoInterfaceReference
FactoryImpl::binuno_queryInterface(
75 UnoInterfaceReference
const & unoI
,
76 typelib_InterfaceTypeDescription
* pTypeDescr
)
78 // init queryInterface() td
79 static typelib_TypeDescription
* s_pQITD
= []() {
80 typelib_TypeDescription
* pTXInterfaceDescr
= nullptr;
81 TYPELIB_DANGER_GET(&pTXInterfaceDescr
, cppu::UnoType
<XInterface
>::get().getTypeLibType());
82 typelib_TypeDescription
* pQITD
= nullptr;
83 typelib_typedescriptionreference_getDescription(
84 &pQITD
, reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTXInterfaceDescr
)
86 TYPELIB_DANGER_RELEASE(pTXInterfaceDescr
);
91 args
[ 0 ] = &reinterpret_cast< typelib_TypeDescription
* >(
92 pTypeDescr
)->pWeakRef
;
93 uno_Any ret_val
, exc_space
;
94 uno_Any
* exc
= &exc_space
;
96 unoI
.dispatch( s_pQITD
, &ret_val
, args
, &exc
);
100 UnoInterfaceReference ret
;
101 if (ret_val
.pType
->eTypeClass
== typelib_TypeClass_INTERFACE
)
103 ret
.set( *static_cast< uno_Interface
** >(ret_val
.pData
),
105 typelib_typedescriptionreference_release( ret_val
.pType
);
109 uno_any_destruct( &ret_val
, nullptr );
115 // exception occurred:
117 typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType
<RuntimeException
>::get().getTypeLibType(),
119 "### RuntimeException expected!" );
121 uno_type_copyAndConvertData(
122 &cpp_exc
, exc
, cppu::UnoType
<decltype(cpp_exc
)>::get().getTypeLibType(),
124 uno_any_destruct( exc
, nullptr );
125 ::cppu::throwException( cpp_exc
);
126 OSL_ASSERT( false ); // way of no return
127 return UnoInterfaceReference(); // for dummy
132 struct ProxyRoot
: public ::cppu::OWeakAggObject
135 virtual Any SAL_CALL
queryAggregation( Type
const & rType
) override
;
137 ProxyRoot( ::rtl::Reference
< FactoryImpl
> factory
,
138 Reference
< XInterface
> const & xTarget
);
140 ::rtl::Reference
< FactoryImpl
> m_factory
;
143 UnoInterfaceReference m_target
;
147 struct binuno_Proxy
: public uno_Interface
149 oslInterlockedCount m_nRefCount
;
150 ::rtl::Reference
< ProxyRoot
> m_root
;
151 UnoInterfaceReference m_target
;
153 TypeDescription m_typeDescr
;
156 ::rtl::Reference
< ProxyRoot
> root
,
157 UnoInterfaceReference target
,
158 OUString oid
, TypeDescription typeDescr
);
165 static void binuno_proxy_free(
166 uno_ExtEnvironment
* pEnv
, void * pProxy
)
168 binuno_Proxy
* proxy
= static_cast< binuno_Proxy
* >(
169 static_cast< uno_Interface
* >( pProxy
) );
170 OSL_ASSERT( proxy
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
== pEnv
);
175 static void binuno_proxy_acquire( uno_Interface
* pUnoI
)
177 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
178 if (osl_atomic_increment( &that
->m_nRefCount
) != 1)
182 uno_ExtEnvironment
* uno_env
=
183 that
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
;
184 assert(uno_env
!= nullptr);
185 (*uno_env
->registerProxyInterface
)(
186 uno_env
, reinterpret_cast< void ** >( &pUnoI
), binuno_proxy_free
,
188 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
189 that
->m_typeDescr
.get() ) );
190 OSL_ASSERT( that
== static_cast< binuno_Proxy
* >( pUnoI
) );
194 static void binuno_proxy_release( uno_Interface
* pUnoI
)
196 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
197 if (osl_atomic_decrement( &that
->m_nRefCount
) == 0)
199 uno_ExtEnvironment
* uno_env
=
200 that
->m_root
->m_factory
->m_uno_env
.get()->pExtEnv
;
201 assert(uno_env
!= nullptr);
202 (*uno_env
->revokeInterface
)( uno_env
, pUnoI
);
207 static void binuno_proxy_dispatch(
208 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberType
,
209 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
211 binuno_Proxy
* that
= static_cast< binuno_Proxy
* >( pUnoI
);
212 switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription
const * >(
213 pMemberType
)->nPosition
)
215 case 0: // queryInterface()
220 *static_cast< Type
const * >( pArgs
[ 0 ] );
221 Any
ret( that
->m_root
->queryInterface( rType
) );
222 uno_type_copyAndConvertData(
223 pReturn
, &ret
, cppu::UnoType
<decltype(ret
)>::get().getTypeLibType(),
224 that
->m_root
->m_factory
->m_cpp2uno
.get() );
225 *ppException
= nullptr; // no exc
227 catch (RuntimeException
&)
229 Any
exc( ::cppu::getCaughtException() );
230 uno_type_any_constructAndConvert(
231 *ppException
, const_cast< void * >(exc
.getValue()),
232 exc
.getValueTypeRef(),
233 that
->m_root
->m_factory
->m_cpp2uno
.get() );
238 binuno_proxy_acquire( pUnoI
);
239 *ppException
= nullptr; // no exc
242 binuno_proxy_release( pUnoI
);
243 *ppException
= nullptr; // no exc
246 that
->m_target
.dispatch( pMemberType
, pReturn
, pArgs
, ppException
);
254 binuno_Proxy::binuno_Proxy(
255 ::rtl::Reference
< ProxyRoot
> root
,
256 UnoInterfaceReference target
,
257 OUString oid
, TypeDescription typeDescr
)
259 m_root(std::move( root
)),
260 m_target(std::move( target
)),
261 m_oid(std::move( oid
)),
262 m_typeDescr(std::move( typeDescr
))
264 uno_Interface::acquire
= binuno_proxy_acquire
;
265 uno_Interface::release
= binuno_proxy_release
;
266 uno_Interface::pDispatcher
= binuno_proxy_dispatch
;
269 ProxyRoot::ProxyRoot(
270 ::rtl::Reference
< FactoryImpl
> factory
,
271 Reference
< XInterface
> const & xTarget
)
272 : m_factory(std::move( factory
))
274 m_factory
->m_cpp2uno
.mapInterface(
275 reinterpret_cast< void ** >( &m_target
.m_pUnoI
), xTarget
.get(),
276 cppu::UnoType
<decltype(xTarget
)>::get() );
277 OSL_ENSURE( m_target
.is(), "### mapping interface failed!" );
281 Any
ProxyRoot::queryAggregation( Type
const & rType
)
283 Any
ret( OWeakAggObject::queryAggregation( rType
) );
284 if (! ret
.hasValue())
286 typelib_TypeDescription
* pTypeDescr
= nullptr;
287 TYPELIB_DANGER_GET( &pTypeDescr
, rType
.getTypeLibType() );
290 Reference
< XInterface
> xProxy
;
291 uno_ExtEnvironment
* cpp_env
= m_factory
->m_cpp_env
.get()->pExtEnv
;
292 assert(cpp_env
!= nullptr);
294 // mind a new delegator, calculate current root:
295 Reference
< XInterface
> xRoot(
296 static_cast< OWeakObject
* >(this), UNO_QUERY_THROW
);
298 (*cpp_env
->getObjectIdentifier
)( cpp_env
, &oid
.pData
, xRoot
.get() );
299 OSL_ASSERT( !oid
.isEmpty() );
301 (*cpp_env
->getRegisteredInterface
)(
302 cpp_env
, reinterpret_cast< void ** >( &xProxy
),
303 oid
.pData
, reinterpret_cast<
304 typelib_InterfaceTypeDescription
* >(pTypeDescr
) );
307 // perform query on target:
308 UnoInterfaceReference
proxy_target(
309 m_factory
->binuno_queryInterface(
310 m_target
, reinterpret_cast<
311 typelib_InterfaceTypeDescription
* >(pTypeDescr
) ) );
312 if (proxy_target
.is())
314 // ensure root's object entries:
315 UnoInterfaceReference root
;
316 m_factory
->m_cpp2uno
.mapInterface(
317 reinterpret_cast< void ** >( &root
.m_pUnoI
),
318 xRoot
.get(), cppu::UnoType
<decltype(xRoot
)>::get() );
320 UnoInterfaceReference
proxy(
321 // ref count initially 1:
322 new binuno_Proxy( this, std::move(proxy_target
), oid
, pTypeDescr
),
324 uno_ExtEnvironment
* uno_env
=
325 m_factory
->m_uno_env
.get()->pExtEnv
;
326 assert(uno_env
!= nullptr);
327 (*uno_env
->registerProxyInterface
)(
328 uno_env
, reinterpret_cast< void ** >( &proxy
.m_pUnoI
),
329 binuno_proxy_free
, oid
.pData
,
330 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
333 m_factory
->m_uno2cpp
.mapInterface(
334 reinterpret_cast< void ** >( &xProxy
),
335 proxy
.get(), pTypeDescr
);
339 ret
.setValue( &xProxy
, pTypeDescr
);
341 catch (...) // finally
343 TYPELIB_DANGER_RELEASE( pTypeDescr
);
346 TYPELIB_DANGER_RELEASE( pTypeDescr
);
352 FactoryImpl::FactoryImpl()
354 OUString uno
= u
"" UNO_LB_UNO
""_ustr
;
355 OUString cpp
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
358 reinterpret_cast< uno_Environment
** >( &m_uno_env
), uno
.pData
, nullptr );
359 OSL_ENSURE( m_uno_env
.is(), "### cannot get binary uno env!" );
362 reinterpret_cast< uno_Environment
** >( &m_cpp_env
), cpp
.pData
, nullptr );
363 OSL_ENSURE( m_cpp_env
.is(), "### cannot get C++ uno env!" );
366 reinterpret_cast< uno_Mapping
** >( &m_uno2cpp
),
367 m_uno_env
.get(), m_cpp_env
.get(), nullptr );
368 OSL_ENSURE( m_uno2cpp
.is(), "### cannot get bridge uno <-> C++!" );
371 reinterpret_cast< uno_Mapping
** >( &m_cpp2uno
),
372 m_cpp_env
.get(), m_uno_env
.get(), nullptr );
373 OSL_ENSURE( m_cpp2uno
.is(), "### cannot get bridge C++ <-> uno!" );
378 Reference
< XAggregation
> FactoryImpl::createProxy(
379 Reference
< XInterface
> const & xTarget
)
381 return new ProxyRoot( this, xTarget
);
386 OUString
FactoryImpl::getImplementationName()
388 return u
"com.sun.star.comp.reflection.ProxyFactory"_ustr
;
391 sal_Bool
FactoryImpl::supportsService( const OUString
& rServiceName
)
393 return cppu::supportsService(this, rServiceName
);
396 Sequence
< OUString
> FactoryImpl::getSupportedServiceNames()
398 return { u
"com.sun.star.reflection.ProxyFactory"_ustr
};
401 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
402 stoc_FactoryImpl_get_implementation(
403 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
405 return cppu::acquire(new FactoryImpl
);
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */