|
Contents |
||
Interfaces Services Implementation |
||
Introduction |
||
In this tutorial, a general example of how to write a UNO component and how to use it in applications, e.g. StarOffice. The example is written in C++, but differences for implementing the component in Java will be mentioned. The component is a basic counter, whose value can be set, read, incremented and decremented. |
||
Interfaces |
||
The
first step, in writing any component (in almost any language
environment) is to specifiy one or more interfaces that the
component must implement. Interfaces separate the specific implementation (there can more than one for a service) from the usage. The client using the component does not have any insight how the component is implemented. Interfaces are specified using an Interface definition language (IDL). UNO uses UNO-IDL as the interface definition language. An interface for a Counter might look like this: file counter.idl: #include <com/sun/star/uno/XInterface.idl> module foo { /** * Interface to count things. */ [ uik(3806AFF0-75A0-11d3-87B300A0-24494732), ident("XCountable", 1.0) ] interface XCountable : com::sun::star::uno::XInterface { long getCount(); void setCount( [in] long nCount ); long increment(); long decrement(); }; };
Any
interface that is specified is derived from XInterface, the basic
interface in UNO. The XInterface has methods for lifetime control
of the interface ( |
||
Services |
||
Any UNO component (service) exports one or more interfaces that the clients are using. All services are specified using the service directive in an IDL file: module foo { service Counter { // exported interfaces: interface XCountable; }; };
|
||
Implementation |
||
A component that is implemented in C++ is normally packaged in a shared library. This shared lib exports two symbols, which are explained further below. Java implementations are normally packaged in a JAR file. In this case the manifest file identifies a class implementing two methods with similar semantics. A simple implementation of the counting UNO service foo.Counter might be:
#include <rtl/ustring.hxx> #include <cppuhelper/implbase1.hxx> #include <cppuhelper/factory.hxx> #include <com/sun/star/lang/XSingleServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/registry/XRegistryKey.hpp> #include <foo/XCountable.hpp> The generated header file declares an abstract C++ class and a function called getCppuType(). Any generated type has its getCppuType() describing the type, e.g. const com::sun::star::uno::Type & SAL_CALL getCppuType( const com::sun::star::uno::Reference< foo::XCountable > * );
The first is called to get a description of the component. This function returns a xml formatted string which describes the component. This function could be generated from the xml description with the xml2cmp tool. Each component should provide such a xml dexcription. The second is called from a loader service to get information about the used environment of the component. The third is called whenever the component is registered in some registry file and the latter is called to obtain a factory to get instances of the component. They are typically implemented as follows: /** * This function returns the name of the used environment. * @param ppEnvTypeName name of the environment * @param ppEnv could be point to a special environment, this parameter is normally set to null */ extern "C" void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv ) { *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; } /** * This function creates an implementation section in the registry and another subkey * for each supported service. * @param pServiceManager generic uno interface providing a service manager * @param pRegistryKey generic uno interface providing registry key to write */ extern "C" sal_Bool SAL_CALL component_writeInfo( void* pServiceManager, void* pRegistryKey ) { if (pRegistryKey) { try { Reference< XRegistryKey > xNewKey( reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM("/foo.MyCounterImpl/UNO/SERVICES") ) ) ); xNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM("foo.Counter") ) ); return sal_True; } } return sal_False; }
/IMPLEMENTATIONS/ /foo.MyCounterImpl // implementation name /UNO /SERVICES /foo.Counter // service name /bar.AnotherCounterImpl // implementation name /UNO /SERVICES /foo.Counter // service name ... /** * Function to create a new component instance; is needed by factory helper implementation. * @param xMgr service manager to if the components needs other component instances */ Reference< XInterface > MyCounterImpl_create( const Reference< XMultiServiceFactory > & xMgr ) { return Reference< XInterface >( new MyCounterImpl( xMgr ) ); } /** * This function is called to get service factories for an implementation. * @param pImplName name of implementation * @param pServiceManager generic uno interface providing a service manager to instantiate components * @param pRegistryKey registry data key to read and write component persistent data * @return a component factory (generic uno interface) */ extern "C" void * SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) { void * pRet = 0; // which implementation is demanded? if (pServiceManager && rtl_str_compare( pImplName, "foo.MyCounterImpl" )) { rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("foo.Counter") ); Reference< XSingleServiceFactory > xFactory( cppu::createSingleFactory( // helper function from cppuhelper lib reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), OUString( RTL_CONSTASCII_USTRINGPARAM("foo.MyCounterImpl") ), MyCounterImpl_create, Sequence< rtl::OUString >( &aServiceName, 1 ) ) ); if (xFactory.is()) { xFactory.acquire(); pRet = xFactory.get(); } } return pRet; }
|
||
|
||
Auhor: Daniel Bölzle ($Date: 2001/08/09 13:17:20 $) |
||
|