Counter Example

From Apache OpenOffice Wiki
Jump to: navigation, search

This example given with the SDK contains two files : counter.cxx and countermain.cxx. These files show differencies with Listing 3 and Listing 4 previously tackled because they have to run with OpenOffice.org now. But they do the same work !

The generated counter, like ProfUnoLifeTime, is able to run even if OpenOffice isn't running. MainCounter in the Figure below is the binary program file to run to test the example. There is no direct arrow between MainCounter and Counter.uno.so, indicating that they are independent of each other : if MainCounter want something from Counter.uno.so, it has to ask to cppuhelper (in other words to Openoffice).

Compilation Chain

This little example uses a registered external module (counter.uno.so build from counter.cxx) and a main program (countermain.cxx) which uses it. We shows with the figure below what tools are involved in the construction of the counter :

Counter Example : the Compilation Chain

The compilation chain for this example (see Figure above) is more complicated than previously, because of the two cpp source files : counter.cxx and countermain.cxx. Please note we have to create a third file in this example : XCounter.idl.

IDL File

The listing of this IDL file is now comprehensive by a reader who have studied IDL Files and Cpp section :

//Listing 6 The IDL Counter File
// IDL
#include <com/sun/star/uno/XInterface.idl>
 
module foo
{
	/**
	 * Interface to count things. 
	 */
	interface XCountable : com::sun::star::uno::XInterface
	{
		long getCount();
		void setCount( [in] long nCount );
		long increment();
		long decrement();
	};
 
	service Counter
	{
		// exported interface:
		interface XCountable;
	};
};

This IDL file describe the interface of counter.cxx which will become counter.uno.so (counter.uno.dll under Windows), a library file after compilation. But again you call one of the four method not directly but through cppuhelper. We give a schematic representation of this IDL file.

Counter Service and Interface

The Counter Class

We give the listing of the counter class :

// Listing 7
// C++
//==================================================================================================
class MyCounterImpl
	: public XCountable
	, public XServiceInfo
{
	// to obtain other services if needed
	Reference< XMultiServiceFactory > m_xServiceManager;
 
	sal_Int32 m_nRefCount;
	sal_Int32 m_nCount;
 
public:
	MyCounterImpl( const Reference< XMultiServiceFactory > & xServiceManager )
		: m_xServiceManager( xServiceManager ), m_nRefCount( 0 )
		{ printf( "< MyCounterImpl ctor called >\n" ); }
	~MyCounterImpl()
		{ printf( "< MyCounterImpl dtor called >\n" ); }
 
// XInterface implementation
	virtual void SAL_CALL acquire() throw ()
		{ ++m_nRefCount; }
	virtual void SAL_CALL release() throw ()
		{ if (! --m_nRefCount) delete this; }
	virtual Any SAL_CALL queryInterface( const Type & rType ) throw (RuntimeException)
		{ return cppu::queryInterface(rType, 
        		static_cast< XInterface* >( static_cast< XServiceInfo* >( this ) ),
        		static_cast< XCountable* >( this ),
                        static_cast< XServiceInfo* >( this ) ); }
 
// XServiceInfo	implementation
    virtual OUString SAL_CALL getImplementationName(  ) throw(RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) throw(RuntimeException);
    static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static(  );
 
// XCountable implementation
	virtual sal_Int32 SAL_CALL getCount() throw (RuntimeException)
		{ return m_nCount; }
	virtual void SAL_CALL setCount( sal_Int32 nCount ) throw (RuntimeException)
		{ m_nCount = nCount; }
	virtual sal_Int32 SAL_CALL increment() throw (RuntimeException)
		{ return (++m_nCount); }
	virtual sal_Int32 SAL_CALL decrement() throw (RuntimeException)
		{ return (--m_nCount); }
};
 
//*************************************************************************
OUString SAL_CALL MyCounterImpl::getImplementationName(  ) 
	throw(RuntimeException)
{
	return OUString( RTL_CONSTASCII_USTRINGPARAM(IMPLNAME) );
}	
 
//*************************************************************************
sal_Bool SAL_CALL MyCounterImpl::supportsService( const OUString& ServiceName ) 
	throw(RuntimeException)
{
	Sequence< OUString > aSNL = getSupportedServiceNames();
	const OUString * pArray = aSNL.getArray();
	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
		if( pArray[i] == ServiceName )
			return sal_True;
	return sal_False;
}	
 
//*************************************************************************
Sequence<OUString> SAL_CALL MyCounterImpl::getSupportedServiceNames(  ) 
	throw(RuntimeException)
{
	return getSupportedServiceNames_Static();
}	
 
//*************************************************************************
Sequence<OUString> SAL_CALL MyCounterImpl::getSupportedServiceNames_Static(  ) 
{
	OUString aName( RTL_CONSTASCII_USTRINGPARAM(SERVICENAME) );
	return Sequence< OUString >( &aName, 1 );
}	
 
/**
 * 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 > SAL_CALL MyCounterImpl_create(
	const Reference< XMultiServiceFactory > & xMgr )
{
	return Reference< XCountable >( new MyCounterImpl( xMgr ) );
}
 
//##################################################################################################
//#### EXPORTED ####################################################################################
//##################################################################################################
/**
 * Gives the environment this component belongs to.
 */
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   the service manager
 * @param pRegistryKey      the registry key
 */
extern "C" sal_Bool SAL_CALL component_writeInfo(void * pServiceManager, void * pRegistryKey)
{
	sal_Bool result = sal_False;
 
	if (pRegistryKey)
	{
		try
		{
			Reference< XRegistryKey > xNewKey(
				reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey(
					OUString( RTL_CONSTASCII_USTRINGPARAM("/" IMPLNAME "/UNO/SERVICES") ) ) );
 
			const Sequence< OUString > & rSNL =
				MyCounterImpl::getSupportedServiceNames_Static();
			const OUString * pArray = rSNL.getConstArray();
			for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
				xNewKey->createKey( pArray[nPos] );
 
			return sal_True;
		}
		catch (InvalidRegistryException &)
		{
			// we should not ignore exceptions
		}
	}
	return result;
}
/**
 * This function is called to get service factories for an implementation.
 *
 * @param pImplName       name of implementation
 * @param pServiceManager a service manager, need for component creation
 * @param pRegistryKey    the registry key for this component, need for persistent data
 * @return a component factory 
 */
extern "C" void * SAL_CALL component_getFactory(const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey)
{
	void * pRet = 0;
 
	if (rtl_str_compare( pImplName, IMPLNAME ) == 0)
	{
		Reference< XSingleServiceFactory > xFactory( createSingleFactory(
			reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
			OUString( RTL_CONSTASCII_USTRINGPARAM(IMPLNAME) ),
			MyCounterImpl_create,
			MyCounterImpl::getSupportedServiceNames_Static() ) );
 
		if (xFactory.is())
		{
			xFactory->acquire();
			pRet = xFactory.get();
		}
	}
 
	return pRet;
}

This is a lot of code compared with Listing 3. This class will be compiled as a dynamic library and to be registered (see Making the Counter registrable).

The countermain program

// Listing 8
// C++ countermain.cxx
int SAL_CALL main(int argc, char **argv)
{
	Reference< XSimpleRegistry > xReg = createSimpleRegistry(); 
	OSL_ENSURE( xReg.is(), "### cannot get service instance of \"com.sun.star.regiystry.SimpleRegistry\"!" );
 
	xReg->open(OUString::createFromAscii("counter.uno.rdb"), sal_False, sal_False);
	OSL_ENSURE( xReg->isValid(), "### cannot open test registry \"counter.uno.rdb\"!" );
 
	Reference< XComponentContext > xContext = bootstrap_InitialComponentContext(xReg);
	OSL_ENSURE( xContext.is(), "### cannot creage intial component context!" );
 
	Reference< XMultiComponentFactory > xMgr = xContext->getServiceManager();
	OSL_ENSURE( xMgr.is(), "### cannot get initial service manager!" );
 
	// register my counter component
	Reference< XImplementationRegistration > xImplReg(
		xMgr->createInstanceWithContext(OUString::createFromAscii("com.sun.star.registry.ImplementationRegistration"), xContext), UNO_QUERY);
	OSL_ENSURE( xImplReg.is(), "### cannot get service instance of \"com.sun.star.registry.ImplementationRegistration\"!" );
 
	if (xImplReg.is())
	{
		xImplReg->registerImplementation(
			OUString::createFromAscii("com.sun.star.loader.SharedLibrary"), // loader for component
#ifdef UNX
#ifdef MACOSX
			OUString::createFromAscii("counter.uno.dylib"),		// component location
#else
			OUString::createFromAscii("counter.uno.so"),		// component location
#endif
#else
			OUString::createFromAscii("counter.uno.dll"),		// component location
#endif
			Reference< XSimpleRegistry >()	 // registry omitted,
						 // defaulting to service manager registry used
			);
 
		// get a counter instance
		Reference< XInterface > xx ;
		xx = xMgr->createInstanceWithContext(OUString::createFromAscii("foo.Counter"), xContext);
		Reference< XCountable > xCount( xx, UNO_QUERY );
		OSL_ENSURE( xCount.is(), "### cannot get service instance of \"foo.Counter\"!" );
 
		if (xCount.is())
		{
			xCount->setCount( 42 );
			printf( "%d," , xCount->getCount() );
			printf( "%d," , xCount->increment() );
			printf( "%d\n" , xCount->decrement() );
		}
	}
 
	Reference< XComponent >::query( xContext )->dispose();
	return 0;
}

This is a lot of code compared with Listing 4. One reason is because we have to register now the previous counter class : this is done in this program between lines 16 and 36.

Tip.png Please note this example doesn't require an OpenOffice running.


Return to Constructing Component or to "Using C++ with OOo SDK" main page

Personal tools