From 6ef033669762a0c7ce70c111458437d5e727a4ae Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Fri, 13 Jan 2017 23:40:51 +0100 Subject: cppuhelper: implement environment mapping for constructor functions ae3a0c8da50b36db395984637f5ad74d3b4887bc unfortunately forgot to implement mapping between UNO environments for constructor functions in the UNO service manager, and due to the many componennt conversions to constructor functions since then, the log UNO purpose environment has become mostly useless. Save the environment, create a closure today! https://wiki.openoffice.org/wiki/Uno/Spec/Log_Environment Change-Id: Idc03b5ed9529da8e81cd91efe50cbeceffa2b247 Reviewed-on: https://gerrit.libreoffice.org/33060 Tested-by: Jenkins Reviewed-by: Michael Stahl --- .../source/loadsharedlibcomponentfactory.hxx | 2 +- cppuhelper/source/servicemanager.cxx | 45 +++++-------- cppuhelper/source/servicemanager.hxx | 4 +- cppuhelper/source/shlib.cxx | 77 ++++++++++++++++++++-- 4 files changed, 94 insertions(+), 34 deletions(-) (limited to 'cppuhelper') diff --git a/cppuhelper/source/loadsharedlibcomponentfactory.hxx b/cppuhelper/source/loadsharedlibcomponentfactory.hxx index 7062d86fc494..df6e2269e381 100644 --- a/cppuhelper/source/loadsharedlibcomponentfactory.hxx +++ b/cppuhelper/source/loadsharedlibcomponentfactory.hxx @@ -35,7 +35,7 @@ void loadSharedLibComponentFactory( rtl::OUString const & prefix, rtl::OUString const & implementation, rtl::OUString const & constructor, css::uno::Reference const & serviceManager, - ImplementationConstructorFn ** constructorFunction, + WrapperConstructorFn * constructorFunction, css::uno::Reference * factory); } } diff --git a/cppuhelper/source/servicemanager.cxx b/cppuhelper/source/servicemanager.cxx index 780fe02ad70b..6d2321c3b9b1 100644 --- a/cppuhelper/source/servicemanager.cxx +++ b/cppuhelper/source/servicemanager.cxx @@ -686,9 +686,9 @@ cppuhelper::ServiceManager::Data::Implementation::createInstance( bool singletonRequest) { css::uno::Reference inst; - if (constructor != nullptr) { + if (constructor) { inst.set( - (*constructor)(context.get(), css::uno::Sequence()), + constructor(context.get(), css::uno::Sequence()), SAL_NO_ACQUIRE); } else if (factory1.is()) { inst = factory1->createInstanceWithContext(context); @@ -706,8 +706,8 @@ cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments( bool singletonRequest, css::uno::Sequence const & arguments) { css::uno::Reference inst; - if (constructor != nullptr) { - inst.set((*constructor)(context.get(), arguments), SAL_NO_ACQUIRE); + if (constructor) { + inst.set(constructor(context.get(), arguments), SAL_NO_ACQUIRE); //HACK: The constructor will either observe arguments and return inst // that does not implement XInitialization (or null), or ignore // arguments and return inst that implements XInitialization; this @@ -797,7 +797,7 @@ void cppuhelper::ServiceManager::loadImplementation( "Cannot expand URI" + implementation->info->uri + ": " + e.Message, static_cast< cppu::OWeakObject * >(this)); } - cppuhelper::ImplementationConstructorFn * ctor = nullptr; + cppuhelper::WrapperConstructorFn ctor; css::uno::Reference< css::uno::XInterface > f0; // Special handling of SharedLibrary loader, with support for environment, // constructor, and prefix arguments: @@ -808,27 +808,8 @@ void cppuhelper::ServiceManager::loadImplementation( uri, implementation->info->environment, implementation->info->prefix, implementation->info->name, implementation->info->constructor, this, &ctor, &f0); - if (ctor != nullptr) { + if (ctor) { assert(!implementation->info->environment.isEmpty()); - css::uno::Environment curEnv(css::uno::Environment::getCurrent()); - if (!curEnv.is()) { - throw css::uno::DeploymentException( - "cannot get current environment", - css::uno::Reference()); - } - css::uno::Environment env( - cppuhelper::detail::getEnvironment( - implementation->info->environment, - implementation->info->name)); - if (!env.is()) { - throw css::uno::DeploymentException( - ("cannot get environment " - + implementation->info->environment), - css::uno::Reference()); - } - if (curEnv.get() != env.get()) { - std::abort();//TODO - } } } else { SAL_WARN_IF( @@ -864,7 +845,7 @@ void cppuhelper::ServiceManager::loadImplementation( } css::uno::Reference f1; css::uno::Reference f2; - if (ctor == nullptr) { + if (!ctor) { f1.set(f0, css::uno::UNO_QUERY); if (!f1.is()) { f2.set(f0, css::uno::UNO_QUERY); @@ -1978,7 +1959,15 @@ void cppuhelper::ServiceManager::preloadImplementations() { else { // get function symbol component factory - fpFactory = aModule.getFunctionSymbol(iterator->second->info->constructor); + aTargetEnv = cppuhelper::detail::getEnvironment(iterator->second->info->environment, iterator->second->info->name); + if (aSourceEnv.get() == aTargetEnv.get()) + { + fpFactory = aModule.getFunctionSymbol(iterator->second->info->constructor); + } + else + { + fpFactory = nullptr; + } } css::uno::Reference xSCFactory; @@ -2002,7 +1991,7 @@ void cppuhelper::ServiceManager::preloadImplementations() { } if (!iterator->second->info->constructor.isEmpty() && fpFactory) - iterator->second->constructor = reinterpret_cast(fpFactory); + iterator->second->constructor = WrapperConstructorFn(reinterpret_cast(fpFactory)); iterator->second->factory1 = xSCFactory; iterator->second->factory2 = xSSFactory; diff --git a/cppuhelper/source/servicemanager.hxx b/cppuhelper/source/servicemanager.hxx index ca0021370545..5f6efd094dd5 100644 --- a/cppuhelper/source/servicemanager.hxx +++ b/cppuhelper/source/servicemanager.hxx @@ -50,6 +50,8 @@ typedef css::uno::XInterface * SAL_CALL ImplementationConstructorFn( } +typedef std::function const&)> WrapperConstructorFn; + typedef cppu::WeakComponentImplHelper< css::lang::XServiceInfo, css::lang::XMultiServiceFactory, css::lang::XMultiComponentFactory, css::container::XSet, @@ -149,7 +151,7 @@ public: enum Status { STATUS_NEW, STATUS_WRAPPER, STATUS_LOADED }; std::shared_ptr< ImplementationInfo > info; - ImplementationConstructorFn * constructor; + WrapperConstructorFn constructor; css::uno::Reference< css::lang::XSingleComponentFactory > factory1; css::uno::Reference< css::lang::XSingleServiceFactory > factory2; css::uno::Reference< css::lang::XComponent > component; diff --git a/cppuhelper/source/shlib.cxx b/cppuhelper/source/shlib.cxx index 0cffab6783f8..fa88cc4b484c 100644 --- a/cppuhelper/source/shlib.cxx +++ b/cppuhelper/source/shlib.cxx @@ -160,6 +160,70 @@ css::uno::Reference invokeComponentFactory( } } +extern "C" void getInstance(va_list * args) { + cppuhelper::ImplementationConstructorFn * fn = va_arg(*args, cppuhelper::ImplementationConstructorFn *); + void * ctxt = va_arg(*args, void *); + assert(ctxt); + void * argseq = va_arg(*args, void *); + assert(argseq); + void ** instance = va_arg(*args, void **); + assert(instance); + assert(*instance == nullptr); + *instance = (*fn)(static_cast(ctxt), + *static_cast const*>(argseq)); +} + +cppuhelper::WrapperConstructorFn mapConstructorFn( + css::uno::Environment const & source, css::uno::Environment const & target, + cppuhelper::ImplementationConstructorFn *const constructorFunction) +{ + if (!(source.is() && target.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get environments", + css::uno::Reference()); + } + if (source.get() == target.get()) { + return cppuhelper::WrapperConstructorFn(constructorFunction); + } else { + // note: it should be valid to capture these mappings because they are + // ref-counted, and the returned closure will always be invoked in the + // "source" environment + css::uno::Mapping mapTo(source, target); + css::uno::Mapping mapFrom(target, source); + if (!(mapTo.is() && mapFrom.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get mappings", + css::uno::Reference()); + } + return [mapFrom, mapTo, target, constructorFunction] + (css::uno::XComponentContext *const context, css::uno::Sequence const& args) + { + void *const ctxt = mapTo.mapInterface( + context, + cppu::UnoType::get()); + if (args.getLength() > 0) { + std::abort(); // TODO map args + } + void * instance = nullptr; + target.invoke(getInstance, constructorFunction, ctxt, &args, &instance); + if (ctxt != nullptr) { + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, ctxt); + } + css::uno::XInterface * res = nullptr; + if (instance == nullptr) { + return res; + } + mapFrom.mapInterface( + reinterpret_cast(&res), instance, + cppu::UnoType::get()); + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, instance); + return res; + }; + } +} + } void cppuhelper::detail::loadSharedLibComponentFactory( @@ -167,13 +231,13 @@ void cppuhelper::detail::loadSharedLibComponentFactory( rtl::OUString const & prefix, rtl::OUString const & implementation, rtl::OUString const & constructor, css::uno::Reference const & serviceManager, - ImplementationConstructorFn ** constructorFunction, + WrapperConstructorFn * constructorFunction, css::uno::Reference * factory) { assert(constructor.isEmpty() || !environment.isEmpty()); assert( (constructorFunction == nullptr && constructor.isEmpty()) - || *constructorFunction == nullptr); + || !*constructorFunction); assert(factory != nullptr && !factory->is()); #if defined DISABLE_DYNLOADING assert(!environment.isEmpty()); @@ -273,8 +337,13 @@ void cppuhelper::detail::loadSharedLibComponentFactory( + "\" in component library <" + uri + ">"), css::uno::Reference()); } - *constructorFunction = reinterpret_cast( - fp); + css::uno::Environment curEnv(css::uno::Environment::getCurrent()); + *constructorFunction = mapConstructorFn( + curEnv, + (environment.isEmpty() + ? getEnvironmentFromModule(mod, curEnv, implementation, prefix) + : getEnvironment(environment, implementation)), + reinterpret_cast(fp)); } mod.release(); #endif -- cgit