2020-04-26

44: Defining Any UNO Component in C++

<The previous article in this series | The table of contents of this series | The next article in this series>

Typically in order to create a listener. Some Knowledge on UNO garbage collection, weak pointing, etc. is due and here.

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: C++

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to define any UNO component in C++.
Stage Direction
Here are Hypothesizer 7, Objector 44A, and Objector 44B in front of a computer.


Orientation


Hypothesizer 7
In this article, we will know how to define any UNO component in C++.

Please be sure that you accurately understand what I mean by 'UNO component'. In fact, I do not mean only '::com::sun::star::lang::XComponent' implementations, although, of course, any '::com::sun::star::lang::XComponent' implementation is a kind of UNO component.

Objector 44A
Huh? Is that a Zen koan?

Hypothesizer 7
Sir, the naming of 'XComponent' is not . . . on the mark, in my opinion: the actual meaning of '::com::sun::star::lang::XComponent' is 'being arbitrarily disposable', which is not any necessary trait of being a component as a general concept. I think that the name should have been like 'XArbitrarilyDisposable'.

Objector 44A
That name is clumsy!

Hypothesizer 7
That name seems to represent the real meaning of that UNO interface the most accurately . . .

Objector 44A
At least, make it 'XDisposable', which sounds neater.

Hypothesizer 7
Actually, the "Arbitrarily" part represents the gist of the meaning. In fact, I am not of any value system in which being neat takes precedence over being accurate.

Objector 44A
In the first place, I don't understand what "being arbitrarily disposable" means.

Hypothesizer 7
You will understand it in a section.

Objector 44B
In the first place, I don't understand why I have to define a UNO component myself. I just use some existing UNO components, existing in LibreOffice, right?

Hypothesizer 7
Madam, you need to define a UNO component typically when you want to create a listener.

Objector 44B
"listener"?

Hypothesizer 7
For example, when you want to get the whole information from a UNO dispatch command execution, you create a listener or some listeners that is or are informed of the information.

Objector 44B
So what?

Hypothesizer 7
The class of each of such listeners has to be a UNO component.

Objector 44B
. . . I don't see any other usage than for UNO dispatch command executions.

Hypothesizer 7
Do you not? In fact, you can listen to many more events like document openings, document closings, key inputs, mouse clicks, spread sheet cell selection changes, Office instance termination tries, etc..

Objector 44B
. . . Anyway, it's only about listeners, isn't it?

Hypothesizer 7
Not particularly. I have created a UNO objects context class; I will create some UNO services in some future articles.

Objector 44B
What do they have to do with UNO components?

Hypothesizer 7
Any UNO objects context class is a UNO component; any UNO service is, roughly speaking, a registered UNO component.


Main Body


1: Undersanding the C++ UNO Garbage Collection Mechanism


Hypothesizer 7
First, let us understand the C++ UNO garbage collection mechanism.

Objector 44A
Huh? Let us know just how to exactly create a UNO component, without any ridiculous lecture!

Hypothesizer 7
. . . I do not deem it to be ridiculous; it is a necessary introduction.

Objector 44A
Whatever . . .

Hypothesizer 7
Each of the other UNO-supported programming languages like Java has its own built-in garbage collection mechanism, while C++ does not.

Objector 44A
I know . . .

Hypothesizer 7
So, C++ UNO has implemented a garbage collection mechanism, for which you have to increment and decrement the usage count of each local UNO object or UNO proxy.

Objector 44A
"UNO proxy"?

Hypothesizer 7
When you handle a remote UNO object, you do not directly handle the remote UNO object, but directly handle some UNO proxies, which have to be garbage collected appropriately. In fact, you do not have to worry about the garbage collection of the remote UNO object itself because it is taken care of by the UNO bridge if only the UNO proxies are garbage collected appropriately.

Objector 44A
I understand.

Hypothesizer 7
When the usage count of the UNO object or UNO proxy is decreased to '0', the UNO object or UNO proxy is disposed.

Objector 44A
So, the usage count is the number of pointers to the UNO object or UNO proxy, I presume?

Hypothesizer 7
I guess so, althoug the exact number does not practically matter, because what practically matters is only the timing when it becomes '0'.

Objector 44A
So, if the demise point is obvious, I could just increment it to '1' at the begining and decrement it to '0' at the end, skipping all the tedious incrementings and decrementings between?

Hypothesizer 7
Practically speaking, yes.


2: Understanding the Meanings of the '::com::sun::star::uno::Reference' and '::com::sun::star::uno::WeakReference' Datum Types


Hypothesizer 7
As explicitly incrementing and decrementing the usage count is tedious, there is a wrapper of the address of any UNO object or UNO proxy, namely, '::com::sun::star::uno::Reference'.

When the address is set into any '::com::sun::star::uno::Reference' datum, the usage count is automatically incremented, and when the address is unset from any '::com::sun::star::uno::Reference' datum (which automatically happens also when the '::com::sun::star::uno::Reference' datum is disposed), the usage count is automatically decremented.

Objector 44A
I don't need that, because I will rather adopt the skipping-all-the-tedious-incrementings-and-decrementings strategy.

Hypothesizer 7
However, most probably you have to use it, because any UNO interface type of any argument or return of any method in the UNO API is mapped to a '::com::sun::star::uno::Reference' type in C++.

Objector 44A
Huh?

Hypothesizer 7
For example, 'void addEventListener ([in] ::com::sun::star::lang::XEventListener xListener)' of '::com::sun::star::lang::XComponent' is mapped to 'void addEventListener (::com::sun::star::uno::Reference <::com::sun::star::lang::XEventListener> const & xListener)' in C++.

Objector 44A
So, I am forced to use'::com::sun::star::uno::Reference' . . .

Hypothesizer 7
On the other hand, there is also '::com::sun::star::uno::WeakReference', which does not continuously claim any usage.

Objector 44A
"continuously claim"?

Hypothesizer 7
'claim' there means incrementing the usage count without decrementing the usage count immediately.

Objector 44A
Huh?

Hypothesizer 7
'::com::sun::star::uno::WeakReference' increments the usage count just before it really accesses the pointed UNO object and decrements the usage count immediately after the access is finished.

Objector 44A
So, that is useful for . . . what?

Hypothesizer 7
Well, I understand that '::com::sun::star::uno::Reference' represents pointing-as-an-owner, while '::com::sun::star::uno::WeakReference' represents pointing-as-a-user. The owner (in fact, there may be multiple owners) determines when the UNO object should be disposed, while the users do not determine the lifetime of the UNO object, but just uses the UNO object only if it still exists. . . . '::com::sun::star::uno::WeakReference' is useful for establishing such data structures.

The official document tells about avoiding cyclic pointings, but that is just a case (if typical), in my opinion.

Objector 44A
Ah.

Hypothesizer 7
Anyway, in order for a UNO object to be weakly pointed, the UNO component has to implement a UNO interface, '::com::sun::star::uno::XWeak'.

'::com::sun::star::uno::XWeak' has a single method, 'com::sun::star::uno::XAdapter queryAdapter ()', which returns an adopter for the UNO object, where 'adopter' meaning a surrogate UNO object that the '::com::sun::star::uno::WeakReference' instance points to, in order not to grip the original UNO object.

Objector 44A
Well, it seems better to make my any UNO component implement it.


3: Understanding the Meaning of '::com::sun::star::lang::XComponent'


Hypothesizer 7
The meaning of '::com::sun::star::lang::XComponent' is not being a component as the name falsely claims, but being arbitrarily disposable.

Objector 44A
I don't understand what "being arbitrarily disposable" means.

Hypothesizer 7
According to the garbage collection mechanism, usually, a UNO object cannot be arbitrarily disposed, because if it is, a pointer to the UNO object will (because it has to) later try to access the now nonexistent UNO object to decrement the usage count, causing, probably, a segmentation fault.

Objector 44A
Ah, under the reign of the garbage collection mechanism, I not only does not have to explicitly dispose the UNO object, but also am not allowed to explicitly dispose the UNO object; the UNO object has to be disposed by the garbage collection mechanism.

Hypothesizer 7
If a UNO object has to be arbitrarily disposed, it will have to notify all the pointers to it that the pointers have to release the UNO object immediately.

As '::com::sun::star::lang::XComponent' has 3 methods, 'void addEventListener ([in] XEventListener xListener)', 'void removeEventListener ([in] XEventListener aListener)', and 'void dispose ()', the former 2 methods are for registering and deregistering the managers of the pointers, and the last method is for notifying the managers of the pointers before disposing itself.


4: 4 Options for Any UNO Component


Hypothesizer 7
Accordingt to the above considerations, there are 4 options for any UNO component: 1) not being able to be weakly pointed and not being able to be arbitrarily disposed, 2) being able to be weakly pointed and not being able to be arbitrarily disposed, 3) not being able to be weakly pointed and being able to be arbitrarily disposed, 4) being able to be weakly pointed and being able to be arbitrarily disposed.


5: Now, Let Us Create a UNO Component


Hypothesizer 7
Whatever UNO component has to implement '::com::sun::star::uno::XInterface', which has 3 mandatory methods, 'void acquire ()', 'void release ()', and 'any queryInterface ([in] type aType)'.

The former 2 methods are for incrementing and decrementing the usage count and disposing the UNO object appropriately.

The description of 'queryInterface ([in] type aType)' in the UNO API document is . . ., how to say, . . . broken, in my opinion: what does "a interface reference of the requested type" mean? "a interface reference"? . . . Even if I put aside the dissatisfaction on such usage of the term, "reference" and interpret "reference" as 'address', the description does not make sense: "interface address" sounds like 'address of an interface', but there is no such a thing in C++, is there? . . . In Java, 'Xinterface.class' represents the address of the interface, but in C++? . . . A description like "obtain other interfaces" does not make sense, either: C++ cannot obtain any interface itself, can it? . . .

In fact, the method returns the address of the UNO object, wrapped in '::com::sun::star::uno::Reference <%the specified UNO interface%>' wrapped in '::com::sun::star::uno::Any', C++-wise.

Objector 44A
"C++-wise"?

Hypothesizer 7
In fact, the method exists only in C++, as far as I know (at least, does not exist in Java).

Objector 44A
Hmm.

Hypothesizer 7
And usually, a UNO component implements also '::com::sun::star::lang::XTypeProvider', which has 2 methods, 'sequence <type> getTypes ()' and 'sequence <byte> getImplementationId ()'.

Objector 44A
"usually"?

Hypothesizer 7
It is not mandatory if the UNO component is not used from some script languages like LibreOffice or Apache OpenOffice Basic.

Objector 44A
Ah.

Hypothesizer 7
The former method returns the sequence of the type data of the implemented UNO interfaces, C++-wise, '::com::sun::star::uno::Sequence <::com::sun::star::uno::Type>'.

The latter method is deprecated.

Objector 44A
Ah.

Hypothesizer 7
You can implement those methods yourself if you will, but you will probably use a class template that has implemented them, in these 3 helper class template groups: '::cppu::ImplHelper%the number of extra UNO interfaces%', '::cppu::WeakImplHelper%the number of extra UNO interfaces%', and '::cppu::WeakComponentImplHelper%the number of extra UNO interfaces%', where %the number of extra UNO interfaces% means the number of UNO interfaces you want to explicitly implement.

Objector 44A
"explicitly"?

Hypothesizer 7
I mean, the UNO interfaces that are not implemented by the helper itself.

Objector 44A
I see.

Hypothesizer 7
For the option 1 in the previous section, we can use '::cppu::ImplHelper%the number of extra UNO interfaces%', which has implemented 'queryInterface ([in] type aType)' and the whole of '::com::sun::star::lang::XTypeProvider', but not 'acquire ()' or 'release ()'.

This is an example usage.

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option1UnoComponent.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option1UnoComponent_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option1UnoComponent_hpp__
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <rtl/ustring.hxx>
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class Option1UnoComponent: public ImplHelper1 <XServiceInfo> {
					private:
						int i_usageCount = 0;
					public:
						Option1UnoComponent ();
						virtual ~Option1UnoComponent ();
						virtual void SAL_CALL acquire () override;
						virtual void SAL_CALL release () override;
						virtual OUString SAL_CALL getImplementationName () override;
						virtual sal_Bool SAL_CALL supportsService (OUString const & a_serviceName) override;
						virtual Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
				};
			}
		}
	}
#endif

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option1UnoComponent.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option1UnoComponent.hpp"
#include <iostream>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			Option1UnoComponent::Option1UnoComponent (): ImplHelper1 <XServiceInfo> () {
				cout << "### 'Option1UnoComponent::Option1UnoComponent ()' is called." << endl << flush;
			}
			
			Option1UnoComponent::~Option1UnoComponent () {
				cout << "### 'Option1UnoComponent::~Option1UnoComponent ()' is called." << endl << flush;
			}
			
			void SAL_CALL Option1UnoComponent::acquire () {
				cout << "### 'Option1UnoComponent::acquire ()' is called." << endl << flush;
				i_usageCount ++;
			}
			
			void SAL_CALL Option1UnoComponent::release () {
				cout << "### 'Option1UnoComponent::release ()' is called." << endl << flush;
				i_usageCount --;
				if (i_usageCount <= 0) {
					delete this;
				}
			}
			
			OUString SAL_CALL Option1UnoComponent::getImplementationName () {
				return UnoExtendedStringHandler::getOustring (string ("not specified"));
			}
			
			sal_Bool SAL_CALL Option1UnoComponent::supportsService (OUString const & a_serviceName) {
				return sal_False;
			}
			
			Sequence <OUString> SAL_CALL Option1UnoComponent::getSupportedServiceNames () {
				return Sequence <OUString> ();
			}
		}
	}
}

Objector 44A
"::com::sun::star::lang::XServiceInfo"?

Hypothesizer 7
That is not any point here: I have used it just because I have to specify at least one extra UNO interface.

For the option 2 in the previous section, we can use '::cppu::WeakImplHelper%the number of extra UNO interfaces%', which has implemented the whole of 'XInterface', the whole of '::com::sun::star::lang::XTypeProvider', and the whole of '::com::sun::star::uno::XWeak'.

This is an example usage.

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option2UnoComponent.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option2UnoComponent_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option2UnoComponent_hpp__
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <rtl/ustring.hxx>
	#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoGeneralEventsListener.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class Option2UnoComponent: public WeakImplHelper1 <XServiceInfo> {
					public:
						Option2UnoComponent ();
						virtual ~Option2UnoComponent ();
						virtual OUString SAL_CALL getImplementationName () override;
						virtual sal_Bool SAL_CALL supportsService (OUString const & a_serviceName) override;
						virtual Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
						virtual void referenceInUnoGeneralEventsListenerArgumentMethod (Reference <UnoGeneralEventsListener> const & a_generalEventsListenerInUnoGeneralEventsListener);
						virtual void referenceInXEventListenerArgumentMethod (Reference <::com::sun::star::lang::XEventListener> const & a_generalEventsListenerInXEventListener);
				};
			}
		}
	}
#endif

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option2UnoComponent.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option2UnoComponent.hpp"
#include <iostream>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			Option2UnoComponent::Option2UnoComponent () : WeakImplHelper1 <XServiceInfo> () {
				cout << "### 'Option2UnoComponent::Option2UnoComponent ()' is called." << endl << flush;
			}
			
			Option2UnoComponent::~Option2UnoComponent () {
				cout << "### 'Option2UnoComponent::~Option2UnoComponent ()' is called." << endl << flush;
			}
			
			OUString SAL_CALL Option2UnoComponent::getImplementationName () {
				return UnoExtendedStringHandler::getOustring (string ("not specified"));
			}
			
			sal_Bool SAL_CALL Option2UnoComponent::supportsService (OUString const & a_serviceName) {
				return sal_False;
			}
			
			Sequence <OUString> SAL_CALL Option2UnoComponent::getSupportedServiceNames () {
				return Sequence <OUString> ();
			}
			
			void Option2UnoComponent::referenceInUnoGeneralEventsListenerArgumentMethod (Reference <UnoGeneralEventsListener> const & a_generalEventsListenerInUnoGeneralEventsListener) {
			}
			
			void Option2UnoComponent::referenceInXEventListenerArgumentMethod (Reference <::com::sun::star::lang::XEventListener> const & a_generalEventsListenerInXEventListener) {
			}
		}
	}
}

Objector 44A
That sounds good. That will be my usual choice, probably.

Hypothesizer 7
For the option 3 in the previous section, we will have to use the beforementioned '::cppu::ImplHelper%the number of extra UNO interfaces%', adding 'XComponent' as an extra UNO interface.

This is an example usage.

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option3UnoComponent.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option3UnoComponent_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option3UnoComponent_hpp__
	#include <set>
	#include <com/sun/star/lang/XComponent.hpp>
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <cppuhelper/compbase2.hxx>
	#include <rtl/ustring.hxx>
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class Option3UnoComponent: public ImplHelper2 <XComponent, XServiceInfo> {
					private:
						int i_usageCount = 0;
						set <Reference <::com::sun::star::lang::XEventListener>> i_eventsListeners;
					public:
						Option3UnoComponent ();
						virtual ~Option3UnoComponent ();
						virtual void SAL_CALL acquire () override;
						virtual void SAL_CALL release () override;
						virtual void SAL_CALL dispose () override;
						virtual void SAL_CALL addEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual void SAL_CALL removeEventListener (Reference <::com::sun::star::lang::XEventListener> const & a_eventsListener) override;
						virtual OUString SAL_CALL getImplementationName () override;
						virtual sal_Bool SAL_CALL supportsService (OUString const & a_serviceName) override;
						virtual Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
				};
			}
		}
	}
#endif

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option3UnoComponent.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option3UnoComponent.hpp"
#include <iostream>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			Option3UnoComponent::Option3UnoComponent (): ImplHelper2 <XComponent, XServiceInfo> () {
				cout << "### 'Option3UnoComponent::Option3UnoComponent ()' is called." << endl << flush;
			}
			
			Option3UnoComponent::~Option3UnoComponent () {
				cout << "### 'Option3UnoComponent::~Option3UnoComponent ()' is called." << endl << flush;
			}
			
			void SAL_CALL Option3UnoComponent::acquire () {
				cout << "### 'Option3UnoComponent::acquire ()' is called." << endl << flush;
				i_usageCount ++;
			}
			
			void SAL_CALL Option3UnoComponent::release () {
				cout << "### 'Option3UnoComponent::release ()' is called." << endl << flush;
				i_usageCount --;
				if (i_usageCount <= 0) {
					delete this;
				}
			}
			
			void Option3UnoComponent::dispose () {
				cout << "### 'Option3UnoComponent::dispose ()' is called." << endl << flush;
				::com::sun::star::lang::EventObject l_event;
				l_event.Source = Reference <Option3UnoComponent> (this);
				for (Reference <XEventListener> const & l_eventsListener: i_eventsListeners) {
					l_eventsListener->disposing (l_event);
					i_eventsListeners.erase (l_eventsListener);
				}
			}
			
			void Option3UnoComponent::addEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'Option3UnoComponent::addEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.insert (a_eventsListener);
			}
			
			void Option3UnoComponent::removeEventListener (Reference <XEventListener> const & a_eventsListener) {
				cout << "### 'Option3UnoComponent::removeEventListener (Reference <XEventListener> const & a_eventsListener)' is called." << endl << flush;
				i_eventsListeners.erase (a_eventsListener);
			}
			
			OUString SAL_CALL Option3UnoComponent::getImplementationName () {
				return UnoExtendedStringHandler::getOustring (string ("not specified"));
			}
			
			sal_Bool SAL_CALL Option3UnoComponent::supportsService (OUString const & a_serviceName) {
				return sal_False;
			}
			
			Sequence <OUString> SAL_CALL Option3UnoComponent::getSupportedServiceNames () {
				return Sequence <OUString> ();
			}
		}
	}
}

Objector 44A
Well, there is no particular reason why I have to persist to the option 3.

Hypothesizer 7
For the option 4 in the previous section, we can use '::cppu::WeakComponentImplHelper%the number of extra UNO interfaces%', which has implemented the whole of 'XInterface', the whole of '::com::sun::star::lang::XTypeProvider', the whole of '::com::sun::star::uno::XWeak', and the whole of '::com::sun::star::lang::XComponent'. . . . In fact, there is also '::cppu::PartialWeakComponentImplHelper%the number of extra UNO interfaces%', which extends '::com::sun::star::lang::XComponent', but does not really implement the methods of '::com::sun::star::lang::XComponent', but I do not understand the necessity of it, because why do not we just use '::cppu::WeakImplHelper%the number of extra UNO interfaces%', adding '::com::sun::star::lang::XComponent' as an extra UNO interface?

This is an example usage.

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option4UnoComponent.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option4UnoComponent_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_Option4UnoComponent_hpp__
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <rtl/ustring.hxx>
	#include <osl/mutex.hxx>
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	using namespace ::osl;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class Option4UnoComponent: public WeakComponentImplHelper1 <XServiceInfo> {
					public:
						Option4UnoComponent (Mutex & a_unoMutex);
						virtual ~Option4UnoComponent ();
						virtual OUString SAL_CALL getImplementationName () override;
						virtual sal_Bool SAL_CALL supportsService (OUString const & a_serviceName) override;
						virtual Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
				};
			}
		}
	}
#endif

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option4UnoComponent.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option4UnoComponent.hpp"
#include <iostream>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			Option4UnoComponent::Option4UnoComponent (Mutex & a_unoMutex): WeakComponentImplHelper1 <XServiceInfo> (a_unoMutex) {
				cout << "### 'Option4UnoComponent::Option4UnoComponent ()' is called." << endl << flush;
			}
			
			Option4UnoComponent::~Option4UnoComponent () {
				cout << "### 'Option4UnoComponent::~Option4UnoComponent ()' is called." << endl << flush;
			}
			
			OUString SAL_CALL Option4UnoComponent::getImplementationName () {
				return UnoExtendedStringHandler::getOustring (string ("not specified"));
			}
			
			sal_Bool SAL_CALL Option4UnoComponent::supportsService (OUString const & a_serviceName) {
				return sal_False;
			}
			
			Sequence <OUString> SAL_CALL Option4UnoComponent::getSupportedServiceNames () {
				return Sequence <OUString> ();
			}
		}
	}
}

Objector 44A
Looks OK.

Hypothesizer 7
There is one more class templates group we can use: '::cppu::ImplInheritanceHelper%the number of extra UNO interfaces%', which is for adding some UNO interfaces to an existing UNO component.

This is an example usage, where the arguments to the constructor of '::cppu::ImplInheritanceHelper1' going to the constructor of the existing UNO component.

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoComponentBase.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_UnoComponentBase_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_UnoComponentBase_hpp__
	#include <string>
	#include <cppuhelper/compbase1.hxx>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <rtl/ustring.hxx>
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class UnoComponentBase: public WeakImplHelper1 <XServiceInfo> {
					private:
						string const i_unoComponentName;
					public:
						UnoComponentBase (string const & a_unoComponentName);
						virtual ~UnoComponentBase ();
						virtual OUString SAL_CALL getImplementationName () override;
						virtual sal_Bool SAL_CALL supportsService (OUString const & a_serviceName) override;
						virtual Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
				};
			}
		}
	}
#endif

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoComponentBase.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoComponentBase.hpp"
#include <iostream>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			UnoComponentBase::UnoComponentBase (string const & a_unoComponentName): WeakImplHelper1 <XServiceInfo> (), i_unoComponentName (a_unoComponentName) {
				cout << "### An instance of a local UNO component, '" << i_unoComponentName << "', is being created." << endl << flush;
			}
			
			UnoComponentBase::~UnoComponentBase () {
				cout << "### An instance of a local UNO component, '" << i_unoComponentName << "', is being deleted." << endl << flush;
				
			}
			
			OUString SAL_CALL UnoComponentBase::getImplementationName () {
				return UnoExtendedStringHandler::getOustring (string ("not specified"));
			}
			
			sal_Bool SAL_CALL UnoComponentBase::supportsService (OUString const & a_serviceName) {
				return sal_False;
			}
			
			Sequence <OUString> SAL_CALL UnoComponentBase::getSupportedServiceNames () {
				return Sequence <OUString> ();
			}
		}
	}
}

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/ExtendedUnoComponent1.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_ExtendedUnoComponent1_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_ExtendedUnoComponent1_hpp__
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include <cppuhelper/compbase1.hxx>
	#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoComponentBase.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class ExtendedUnoComponent1: public ImplInheritanceHelper1 <UnoComponentBase, ::com::sun::star::lang::XEventListener> {
					public:
						ExtendedUnoComponent1 ();
						virtual ~ExtendedUnoComponent1 ();
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_event) override;
				};
			}
		}
	}
#endif


theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/ExtendedUnoComponent1.cpp

@C++ Source Code
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/ExtendedUnoComponent1.hpp"
#include <iostream>

using namespace ::std;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			ExtendedUnoComponent1::ExtendedUnoComponent1 (): ImplInheritanceHelper1 <UnoComponentBase, ::com::sun::star::lang::XEventListener> (string ("::theBiasPlanet::unoUtilities::localUnoObjectsTest1::ExtendedUnoComponent1")) {
			}
			
			ExtendedUnoComponent1::~ExtendedUnoComponent1 () {
			}
			
			void SAL_CALL ExtendedUnoComponent1::disposing (::com::sun::star::lang::EventObject const & a_event) {
			}
		}
	}
}



Objector 44A
Um? Why don't we just normally extend the existing UNO component, like this?

theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/BadUnoComponent.hpp

@C++ Source Code
#ifndef __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_BadUnoComponent_hpp__
#define __theBiasPlanet_unoUtilitiesTests_localUnoObjectsTest1_BadUnoComponent_hpp__
	#include <com/sun/star/lang/XEventListener.hpp>
	#include <com/sun/star/uno/Sequence.hxx>
	#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/UnoComponentBase.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	
	namespace theBiasPlanet {
		namespace unoUtilitiesTests {
			namespace localUnoObjectsTest1 {
				class BadUnoComponent: public UnoComponentBase, ::com::sun::star::lang::XEventListener {
					public:
						BadUnoComponent ();
						virtual ~BadUnoComponent ();
						virtual void SAL_CALL disposing (::com::sun::star::lang::EventObject const & a_event) override;
				};
			}
		}
	}
#endif


theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/BadUnoComponent.cpp

@C++ Source Code

#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/BadUnoComponent.hpp"
#include <iostream>

using namespace ::std;

namespace theBiasPlanet {
	namespace unoUtilitiesTests {
		namespace localUnoObjectsTest1 {
			BadUnoComponent::BadUnoComponent (): UnoComponentBase (string ("::theBiasPlanet::unoUtilities::localUnoObjectsTest1::BadUnoComponent")) {
			}
			
			BadUnoComponent::~BadUnoComponent () {
			}
			
			void SAL_CALL BadUnoComponent::disposing (::com::sun::star::lang::EventObject const & a_event) {
			}
		}
	}
}


Hypothesizer 7
That is because your extra UNO interface also extends '::com::sun::star::uno::XInterface', causing you to have to implement '::com::sun::star::uno::XInterface' again.

Objector 44A
Ah, the implementation of '::com::sun::star::uno::XInterface' by the existing UNO component doesn't belatedly implement '::com::sun::star::uno::XInterface' of my extra UNO interface, of course . . .

Hypothesizer 7
The merit for creating a single UNO component base and extending it for all of my UNO components is that I can track the births and the deaths of all the instances of my UNO components.


6: The Conclusion and Beyond


Hypothesizer 7
Now, we know how to define any UNO component in C++.

How can we use it for local UNO objects and for remote UNO objects? We will see it in some future articles.

We will see also how to create any UNO component in Java, in C#, and in Python, in some future articles.


References


<The previous article in this series | The table of contents of this series | The next article in this series>