Hello,

I'd like to present/discuss a recent helper I have developed which IMO
simplifies the implementation of UNO services in C++ a lot.
Using the following (what I call) service declaration, the developer can
concentrate on implementing her service's interfaces, e.g.

class MyImpl : cppu::WeakImplHelper2<XInterface1, XInterface2> {...};

There is no need to implement lang::XServiceInfo nor
lang::XInitialization (if the service expects arguments for creation).

Next, one just has to declare the above class defining a service
declaration object:

namespace sdecl = comphelper::service_decl;
sdecl::ServiceDecl const myDecl(
    sdecl::class_<MyImpl>(),
    "org.openoffice.MyService",
    [optional "my.implementation.name"] );

The ServiceDecl ctor expects as

1st parameter: a comphelper::service_decl::class_ object as first
parameter (which I further explain shortly)

2nd parameter: a single name or a uno::Sequence<rtl::OUString> stating
the supported service names

3rd parameter (optional): an implementation name; if this has been
omitted, the implementation name will be generated out of MyImpl'S
type_info (which I will explain shortly).

The class_ object states the user's implementation class, which by
default is required to define a constructor taking a

    uno::Reference<uno::XComponentContext>

as its sole argument.  If the user requires service arguments for
construction, she can customize the class_ object, using

    sdecl::class_<MyImpl, sdecl::with_args<true> >()

In this case, the user's implementation class is required to define a
constuctor taking

    uno::Sequence<uno::Any>,
    uno::Reference<XComponentContext>

If the user needs to execute "special" post processing code, e.g. for
registering the newly created object as a listener, then she can specify
a function/functor, too:

    sdecl::class_<MyImpl, ...>(&postProcessing)

That functor needs to be of the following form, e.g.

uno::Reference<uno::XInterface> postProcessing( MyClass * p );

and gets the _yet unacquired_ pointer.

If the implementation name ought to be generated, then the mangled C++
name including the user's class is taken into account as well as the
library name, e.g. a generated name may look like:

"deployment680mi.uno.dll;[EMAIL PROTECTED]@dp_manager@@"
(MSVC, using type_info::raw_name())

"deployment680li.uno.so;N10dp_manager7factory25PackageManagerFactoryImplE"
(gcc 3.4.1, using type_info::name())

There is a flaw when the user uses an anonymous namespace for the
implementation class:
- At least on Windows there is the possibility that the generated
implementation name is not unique (e.g. same anonymous class name in two
different compilation units within same dll).
- g++ mangles the whole compilation path into the anonymous symbol (+
time stamp etc.).  This will avoid the possibility to just quickly
compile and link a library with debug and exchange without
re-registering it, which I fear leads to subtle confusion.
IMO, sad but true, using a anonymous namespace is a bad idea here, so I
currently disallow this leading to a runtime error when the library is
loaded, stating these problems (currently on Windows only; easy to
detect).  Implementation classes have to be declared in a _named_
namespace (if any).

When it comes to exporting the necessary component_xxx() functions,
there are new helper functions that can deal with a variable number of
ServiceDecl objects:

extern "C" {
void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

sal_Bool SAL_CALL component_writeInfo(
    lang::XMultiServiceFactory * pServiceManager,
    registry::XRegistryKey * pRegistryKey )
{
    return component_writeInfoHelper(
        pServiceManager, pRegistryKey, myDecl, myDecl2, ... );
}

void * SAL_CALL component_getFactory(
    sal_Char const * pImplName,
    lang::XMultiServiceFactory * pServiceManager,
    registry::XRegistryKey * pRegistryKey )
{
    return component_getFactoryHelper(
        pImplName, pServiceManager, pRegistryKey, myDecl, myDecl2, ...);
}
} // extern "C"

By default, the component_xxxHelper() functions can cope with up to 8
declarations (can be increased using
COMPHELPER_SERVICEHELPER_COMPONENT_HELPER_MAX_ARGS before including
comphelper/servicedecl.hxx).

You can have a look at the implementation on cws dbo510 (tag
cws_src680_dbo510):
comphelper/inc/comphelper/servicedecl.hxx
comphelper/inc/comphelper/makesequence.hxx
comphelper/source/misc/servicedecl.cxx

For testing purposes, I have adopted the deployment API implementation
(module desktop) which comes with quite a lot services.

So what do you think?  Comments, please.

regards,
-Daniel

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to