| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> |
| <title>A guide to C++ UNO</title> |
| <style type="text/css"> |
| <!-- |
| li {margin-bottom: 0.2cm;} |
| h1 {color:#ffffff;font-size:20pt;font-weight:bold;font-family:Arial,sans-serif; |
| margin-top: 0.2cm; margin-bottom: 0.2cm} |
| h2 {color:#ffffff;font-size:16pt;font-family:Arial,sans-serif; |
| padding-left: 0.1cm; padding-top: 0.2cm; padding-bottom: 0.2cm; |
| margin-right: 0.1cm; |
| background-color: #666699; width: 100%} |
| --> |
| </style> |
| |
| </head> |
| <body> |
| <table BORDER=0 CELLSPACING=0 bgcolor=#666699 width=100%> |
| <tr> |
| <td align=center> |
| <h1>A Guide to C++ UNO</h1> |
| </td> |
| <td align=right> |
| <a href="http://www.openoffice.org/"> |
| <img SRC="../../../images/open_office_org_logo.gif" NAME="Grafik1" ALT="OpenOffice.org" BORDER=0 align=right/></a> |
| </td> |
| </tr> |
| </table> |
| <!-- *************************************** |
| * Contents |
| *************************************** --> |
| <h2>Contents</h2> |
| <blockquote> |
| <p><a href="#overview">Overview</a> |
| <br/><a href="#library_overview">Shared library overview </a> |
| <br/><a href="#sal">System abstraction layer (sal)</a> |
| <br/><a href="#mapping">C++ mapping of IDL-types</a> |
| <br/><a href="#cppuhelper">The cppuhelper module</a> |
| <br/><a href="#contexts">UNO contexts</a> |
| <br/><a href="#components">C++ components</a> |
| <br/><a href="#common_patterns">Common programming patterns</a> |
| </blockquote> |
| |
| <!-- *************************************** |
| * Overview |
| *************************************** --> |
| <h2> <a NAME="overview"></a>Overview</h2> |
| <p> This document gives an introduction to the C++ mapping of UNO. |
| You should have read the <em><a href="../../../common/man/concept/unointro.html"> |
| A guide to language independent UNO</a></em>, before reading with this |
| document. It is a good idea to look at the relevant source code after reading |
| this document. Some C++ components which follow the the concepts explained |
| below can be found in the stoc, io or remotebridges modules, for example.</p> |
| |
| <p>TODO :</p> |
| <ul> |
| <li>Documentation of the exported symbols in the Components section</li> |
| </ul> |
| |
| <!-- *************************************** |
| * Library overview |
| *************************************** --> |
| <h2> <a NAME="library_overview"></a>Shared library overview</h2> |
| <img src="../images/udk_baselibraries.gif" align=middle alt="UDK base libraries"/> |
| |
| <p>In the above diagram the (C) means C-linkage, (C++) means C++ linkage. For |
| all libraries you will need a C++ compiler to build.</p> |
| |
| <p> |
| The base for all UDK-libraries is the sal-library, that contains all system abstractions |
| and does not contain any UNO-specific data. The most commonly used C-functions can |
| be accessed via C++ inline wrappers. This allows to call the functions from |
| any other programming language. |
| |
| The salhelper-library offers additional base functionality, that could be implemented inline. |
| |
| <p> |
| The cppu ( = C Plus Plus Uno) library is the core uno library. |
| It offers methods to access the UNO type library and allows to generically create, copy and compare |
| values of UNO data types. Additionally all bridges (= mappings + environments) are administered |
| here. |
| |
| <p>msci_uno, sunpro5_uno and urp_uno are only examples for language binding |
| libraries (MS VC++ 6, sunpro5 solaris).</p> |
| |
| <p> The cppuhelper library is a C++ library, that contains some important base |
| classes for components (see <a href="#cppuhelper">below</a>). C++ components |
| are usually linked against cppuhelper.</p> |
| |
| |
| <!-- *************************************** |
| * System abstraction layer |
| *************************************** --> |
| <h2> <a NAME="sal"></a>System abstraction layer (sal)</h2> |
| |
| <p>The <em>sal</em>-library offers operating system dependent services behind |
| one interface. The aim is to minimize, or eliminate, operating system |
| dependent #ifdefs in libraries above sal. Further more basic features such as |
| strings are implemented in sal. Sal exports only C-symbols, there are inline |
| C++ wrappers for convenience where it is sensible.</p> |
| |
| <h4> File access</h4> |
| <a href="../../ref/sal/c_FileBase.html"><code>osl::FileBase</code></a><br/> |
| <a href="../../ref/sal/c_VolumeInfo.html"><code>osl::VolumeInfo</code></a><br/> |
| <a href="../../ref/sal/c_FileStatus.html"><code>osl::FileStatus</code></a><br/> |
| <a href="../../ref/sal/c_File.html"><code>osl::File</code></a><br/> |
| <a href="../../ref/sal/c_DirectoryItem.html"><code>osl::DirectoryItem</code></a><br/> |
| <a href="../../ref/sal/c_Directory.html"><code>osl::Directory</code></a><br/> |
| |
| |
| <h4> Thread safe refcounting </h4> |
| <code>osl_incrementInterlockedCount</code> and <code>osl_decrementInterlockedCount</code> |
| allow to modify a thread safe 4 byte counter. |
| |
| <h4> Threads and thread synchronization </h4> |
| <a href="../../ref/sal/c_Mutex.html"><code>::osl::Mutex</code></a><br/> |
| <a href="../../ref/sal/c_Condition.html"><code>::osl::Condition</code></a><br/> |
| <a href="../../ref/sal/c_Semaphore.html"><code>::osl::Semaphore</code></a><br/> |
| <a href="../../ref/sal/c_Thread.html"><code>::osl::Thread</code></a>(docu not yet available) |
| |
| <h4> Interprocess communication </h4> |
| <a href="../../ref/sal/c_Socket.html"><code>::osl::Socket</code></a>(docu not yet available)<br/> |
| <a href="../../ref/sal/c_Pipe.html"><code>::osl::Pipe</code></a>(docu not yet available)<br/> |
| |
| |
| <h4> Strings </h4> |
| The string classes in sal ( |
| <a href="../../ref/sal/c_OUString.html"><code>rtl::OUString</code></a> |
| for Unicode-strings and |
| <a href="../../ref/sal/c_OString.html"><code>rtl::OString</code></a> for byte strings) are C++ wrapper for refcounted |
| immutable <a href="../../ref/sal/f_ustring.h.html">C-strings</a>. |
| |
| The <a href="../../ref/sal/c_OUStringBuffer.html"><code>rtl::OUStringBuffer</code></a> and |
| <a href="../../ref/sal/c_OStringBuffer.html"><code>rtl::OStringBuffer</code></a> allow efficient |
| concatenation of strings. |
| |
| |
| <h4> Byte sequence </h4> |
| The |
| <a href="../../ref/sal/c_ByteSequence.html"><code>::rtl::ByteSequence</code></a> |
| is a C++ wrapper around |
| <a href="../../ref/sal/f_byteseq.h.html">C-functions</a> |
| for a refcounted piece of memory. The <code>ByteSequence</code> is binary compatible to |
| <code>com::sun::star::uno::Sequence< sal_Int8></code>, both can be cast into each other. |
| |
| |
| <!-- *************************************** |
| * C++ mapping of IDL-types |
| *************************************** --> |
| <h2> <a NAME="mapping"></a>C++ mapping of IDL-types</h2> |
| |
| <p>The binary specification for the IDL to C++ mapping can be found |
| <a href="../spec/cpp_spec.html">here</a>, where some typical use cases of the |
| C++ mapping are shown.</p> |
| |
| <h4> Interface references </h4> |
| Interface references, see |
| <a href="../../ref/Cppu/c_Reference.html"><code>com::sun::star::uno::Reference</code></a>-template, |
| are used to hold interfaces. The reference constructor (ctor) acquires |
| (increases the refcount by one) the interface and the destructor releases the |
| interface. |
| |
| <p> Example 1 : |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="red">using namespace</font> ::com::sun::star::uno; |
| |
| { |
| <font color="green">// refcount of pSimpleUnoObject is zero</font> |
| OWeakObject *pSimpleUnoObject = <font color="red">new</font> ::cppu::OWeakObject(); |
| |
| <font color="green">// ctor calls acquire, increases refcount</font> |
| Reference< XInterface > reference( (XInterface *) pSimpleUnoObject ); |
| |
| <font color="green">// destructor of reference calls release, refcount drops to zero, |
| // release does a delete this, the object is destroyed;</font> |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p> |
| <a href="../../ref/Cppuhelper/c_OWeakObject.html"><code>cppu::OWeakObject</code></a> |
| is a very simple uno-object, that is often used as a base class for other |
| UNO-objects, as explained |
| <a href="#oweakobject">below</a>. |
| Here it is only important to know, that it correctly implements |
| XInterface. The above code has no resource leak, it is perfectly OK |
| (though certainly not very useful).</p> |
| |
| <p> Example 2: |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="red">using namespace</font> ::rtl; |
| <font color="red">using namespace</font> ::com::sun::star::lang; |
| <font color="red">using namespace</font> ::com::sun::star::uno; |
| <font color="red">using namespace</font> ::com::sun::star::io; |
| { |
| <font color="green"> // get service manager of component context |
| // ( how the context is bootstrapped, is explained below ).</font> |
| Reference < XMultiComponentFactory > rServiceManager = xContext->getServiceManager(); |
| |
| <font color="green"> // create the Pipe service</font> |
| Reference< XInterface > r = rServiceManager->createInstanceWithContext( |
| OUString::createFromAscii( "com.sun.star.io.Pipe" ), xContext ); |
| assert( r.is() ); // the service must exist |
| |
| <font color="green"> // ask the XInterface-reference for the XInputStream interface</font> |
| Reference< XInputStream > rInputStream( r , UNO_QUERY ); |
| assert( rInputStream.is() ); // the service must support XInputStream |
| |
| <font color="green"> // ask the XInterface-reference for the XOutputStream interface</font> |
| Reference< XOutputStream > rOutputStream( r , UNO_QUERY ); |
| assert( rOutputStream.is() ) // test service must support XOutputStream |
| |
| [.... do some calls on the references] |
| |
| <font color="green"> // each references calls release when it is destructed. |
| // The last release destroys the object.</font> |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>In the first line, an initial component context (factory context) is bootstrapped (see |
| <a href="#component_context">below</a> |
| , how this can be done). |
| The second line retrieves the bootstrapped service manager of the context. |
| The next line creates the service |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/io/Pipe.html"> |
| <em> com.sun.star.io.Pipe </em> </a> |
| and returns a reference |
| to XInterface (Note: the <code>operator ->()</code> simply returns the unacquired |
| interface pointer). |
| This service supports |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/io/XInputStream.html">XInputStream</a> |
| and |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/io/XOutputStream.html">XOutputStream</a> |
| , the next lines retrieve these interfaces. |
| The used reference constructor (the magic <code>UNO_QUERY</code> is an |
| element of a dummy enum, that allows to have |
| a 2nd constructor which takes an interface reference as an argument) performs a |
| <code>queryInterface</code> |
| on <code>r</code> for the interface (here XInputStream and XOutputStream), the results |
| are stored within the references.</p> |
| |
| <h4><a name="weak_references"></a> Weak references </h4> |
| |
| <p>In general every uno object allows to hold weak references on it (see |
| <a href="#oweakobject">OWeakObject</a>). |
| Weak references allow to retrieve a hard interface reference if the object has |
| been not destroyed before.</p> |
| |
| <p>Example |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="red">class</font> A |
| { |
| <font color="red">private:</font> |
| WeakReference< XInputStream > m_wrStream; |
| <font color="red">void</font> set( <font color="red">const</font> Reference< XInputStream > &r ) |
| { |
| <font color="green"> // store to weak reference</font> |
| m_wrStream = r; |
| } |
| Reference< XInputStream > get() |
| { |
| <font color="green"> // try to make the weak reference hard</font> |
| Reference< XIntputStream > r = m_wrStream; |
| |
| <font color="green"> // Note : r.is() may be true or not, depending on whether |
| // the object has been destroyed before.</font> |
| return r; |
| } |
| }; |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| <h4> Sequence </h4> |
| <p>For every type in UNO exists another type, the sequence < type >. In C++, |
| this is managed by the <a href="../../ref/Cppu/c_Sequence.html"><code> Sequence |
| </code></a> template, which is a wrapper around a refcounted C-struct. The |
| sequence follows a copy on modify strategy (if the refcount is larger than 1, |
| the sequence is copy-constructed). The sequence can only be used with |
| UNO-types, because it needs a <code>getCppuType</code> for the element type ( |
| which are generated by the build environment).</p> |
| |
| <p>Some basic examples how to use the template</p> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| { |
| <font color="green"> // create an integer sequence with 3 elements, |
| // elements are defaulted to zero.</font> |
| Sequence< sal_Int32 > seqInt( 3 ); |
| |
| <font color="green"> // get a read write pointer (this method checks for |
| // the refcount and does a copy on demand). |
| // however, if you know, that the refcount is one |
| // ( as in this case, the sequence has just been |
| // constructed), you could avoid the check |
| // (which is a C-call overhead) |
| // by writing sal_Int32 *pArray = |
| // (sal_Int32*) seqInt.getConstArray();</font> |
| sal_Int32 *pArray = seqInt.getArray(); |
| |
| <font color="green"> // modify the members</font> |
| pArray[0] = 4; |
| pArray[1] = 5; |
| pArray[2] = 3; |
| } |
| |
| { |
| sal_Int32 sourceArray[3] = {3,5,3}; |
| |
| <font color="green"> // result is the same as above, but initialises from a buffer.</font> |
| Sequence< sal_Int32 > seqInt( sourceArray , 3 ); |
| } |
| |
| { |
| <font color="green"> |
| // construct a sequence of Property structs, |
| // the structs are default constructed</font> |
| Sequence< Property > seqProperty(2); |
| seqProperty.getArray()[0].Name = OUString::createFromAscii( "A" ); |
| seqProperty.getArray()[0].Handle = 0; |
| seqProperty.getArray()[1].Name = OUString::createFromAscii( "B" ); |
| seqProperty.getArray()[1].Handle = 1; |
| |
| <font color="green"> // copy construct the sequence (The refcount is raised)</font> |
| Sequence< Property > seqProperty2 = seqProperty; |
| |
| <font color="green"> // access a sequence</font> |
| for( sal_Int32 i = 0 ; i < seqProperty.getLength() ; i ++ ) |
| { |
| <font color="green"> // Please NOTE : seqProperty.getArray() would also work, but |
| // it is very expensive, because a |
| // unnecessary copy construction |
| // of the sequence takes place.</font> |
| printf( "%d\n" , seqProperty.getConstArray()[i] ); |
| } |
| } |
| |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| <h4> Any </h4> |
| <p>The<a href="../../ref/Cppu/c_Any.html"><code>Any</code></a> is a generic |
| container, that stores a type and a value. Here are some basic examples, how to |
| you use the Any :</p> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| { |
| sal_Int32 i = 5; |
| OUString string = OUString::createFromAscii( "demo" ); |
| |
| Any aInt,aString; |
| |
| <font color="green"> // put an sal_Int32 into an any</font> |
| aInt <<= i; |
| |
| <font color="green"> // put a string into an any</font> |
| aString <<= string; |
| |
| |
| <font color="green"> // extract an int out of an any</font> |
| sal_Int32 i2; |
| if( aInt >>= i2 ) |
| { |
| printf( "int successfully extracted %d!\n" , i2 ); |
| } |
| |
| <font color="green"> // the any does no conversion from string to int during extraction, |
| // use the typeconverter service for theses purposes.</font> |
| if( !( aString >>= i2 ) ) |
| { |
| printf( "string could not be converted to an int\n" ); |
| } |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| <h4> Exception </h4> |
| <p>UNO exceptions can simply be thrown like C++ exceptions. Example :</p> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| |
| <font color="red">void</font> ArbitraryService::doSomething( <font color="red">const</font> Any &a ) |
| <font color="green">throws</font>( IllegalArgumentException ) |
| { |
| sal_Int32 i; |
| if( ! (a >>= i ) ) |
| { |
| <font color="green"> // a int was specified to be in the any</font> |
| IllegalArgumentException exception; |
| exception.Message = OUString::createFromAscii( |
| "unexpected type in any" ); |
| exception.ArgumentPosition = 0; |
| <font color="red">throw</font> exception; |
| } |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| |
| |
| <!-- *************************************** |
| * The cppuhelper module |
| *************************************** --> |
| <h2> <a NAME="cppuhelper"></a>The cppuhelper module</h2> |
| |
| <p>cppuhelper contains important base classes for UNO-objects, a bootstrap |
| mechanism for the initial component context (factory context) and some other |
| objects. The cppuhelper and salhelper libraries are the only C++-linkage |
| libraries within the UDK.</p> |
| |
| <h4><a name="oweakobject"></a> Weak object </h4> |
| |
| The |
| <a href="../../ref/Cppuhelper/c_OWeakObject.html"><code>cppu::OWeakObject</code></a> |
| is the suggested minimum base class that every uno object should support. |
| (see cppuhelper/weak.hxx). It implements a basic refcounting object and allows others to |
| hold the object weak (see <a href="weak_references">weak references</a>). |
| <p> Example of an uno-object, that uses OWeakObject as base class. |
| |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="red">class</font> OFileWriter : <font color="green">public</font> OWeakObject, public XOutputStream |
| { |
| <font color="red">public:</font> |
| OFileWriter( char *pcFile ) : m_f( fopen( pcFile , "w" ) ) |
| {} |
| <font color="red">public:</font> <font color="green">// XInterface implementation</font> |
| <font color="red"> virtual</font> Any SAL_CALL queryInterface( |
| <font color="red">const</font> ::com::sun::star::uno::Type& aType ) <font color="red">throw</font>() |
| { |
| Any a = ::cppu::queryInterface( |
| aType, static_cast< XOutputStream * >( this ) ); |
| |
| if( a.hasValue() ) |
| { |
| return a; |
| } |
| |
| return OWeakObject::queryInterface( aType ); |
| } |
| <font color="red">virtual void</font> SAL_CALL acquire() |
| { OWeakObject::acquire(); } |
| <font color="red">virtual void</font> SAL_CALL release() |
| { OWeakObject::release(); } |
| |
| <font color="red">public:</font><font color="green"> // XOutputStream implementation</font> |
| <font color="red"> virtual void</font> SAL_CALL writeBytes( |
| <font color="red">const</font> Sequence< sal_Int8 >& aData) <font color="red">throw</font> () |
| { |
| fwrite( aData.getConstArray() , 1 , aData.getLength() , m_f ); |
| } |
| <font color="red"> virtual void</font> SAL_CALL flush(void) <font color="red">throw</font> () |
| { |
| fflush( m_f ); |
| } |
| |
| <font color="red"> virtual void</font> SAL_CALL closeOutput(void) <font color="red">throw</font> () |
| { |
| fclose( m_f ); |
| } |
| <font color="red">private:</font> |
| FILE *m_f; |
| }; |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>The class implements an |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/io/XOutputStream.html">XOutputStream</a> |
| using stdc library. |
| The constructor creates a file and stores the file handle in a class member.</p> |
| |
| <p> The task of queryInterface is to return the correct interface reference for the requested |
| type, therefore it must cast the <code>this</code>-pointer to the correct interface pointer. |
| The task is simplified by the global queryInterface-template-method, which compares the requested |
| type with the cast this-pointers. If they match, an <em>any</em> with the |
| correct reference is returned, |
| otherwise an empty (void) any is returned. If the latter case is true, the call is delegated |
| to OWeakObject's queryInterface. |
| |
| <p> acquire and release are delegated to OWeakObject to resolve ambiguities. |
| |
| <p> The following three methods simply implement the XOutputStream interface. Note that |
| error checking has been omitted to simplify the code (this is certainly a very poor |
| XOutputSteam implementation). |
| <p> The methods have been implemented inline to shorten the source. There is certainly no |
| advantage in inlining virtual methods and should not be done in general. |
| |
| <p> The object is not scriptable because it does not support the |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/lang/XTypeProvider.html">XTypeProvider</a> |
| -interface. |
| |
| |
| <h4> The Component helper</h4> |
| <p> |
| <a href="../../ref/Cppuhelper/c_OComponentHelper.html"><code>cppu::OComponentHelper</code></a> |
| is the suggested base class for UNO-objects that must |
| support the |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/lang/XComponent.html">XComponent</a> |
| interface. The implementation(see cppuhelper/weak.hxx ) |
| takes care of event listener |
| administration and ensures correctly notifying all listeners in both possible |
| cases (refcount drops to zero or <code>dispose</code> is called). |
| OComponentHelper is derived from OWeakObject.</p> |
| |
| <h4> The implementation helper</h4> |
| <p>The so called <em>implementation helpers</em> are an excellent template |
| variation of the above base classes. The use can be best explained with a |
| sample :</p> |
| |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="red">class</font> OFileWriter : <font color="red">public</font> WeakImplHelper1< XOutputStream > |
| { |
| <font color="red">public:</font> |
| OFileWriter( char *pcFile ) : m_f( fopen( pcFile , "w" ) ) |
| {} |
| |
| <font color="red">public:</font> <font color="green">// XOutputStream implementation</font> |
| <font color="red"> virtual void</font> SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) <font color="red">throw</font> () |
| { |
| fwrite( aData.getConstArray() , 1 , aData.getLength() , m_f ); |
| } |
| <font color="red"> virtual void</font> SAL_CALL flush() <font color="red">throw</font> () |
| { |
| fflush( m_f ); |
| } |
| |
| <font color="red"> virtual void</font> SAL_CALL closeOutput() <font color="red">throw</font> () |
| { |
| fclose( m_f ); |
| } |
| <font color="red">private:</font> |
| FILE *m_f; |
| }; |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>The implementation helper templates fulfill two tasks:</p> |
| <ul> |
| <li> correct queryInterface implementation (using the template parameter |
| and their base classes as possible interfaces to query for). |
| <li> correct XTypeProvider implementation, so that the object |
| is accessible by scripting languages. |
| </ul> |
| |
| The helper exists in 4 variations |
| <ul> |
| <li> WeakImplHelper : base class is OWeakObject |
| <li> WeakComponentImplHelper : base class is OWeakObject, |
| implements the same stuff as OComponentHelper |
| <li> WeakAggImplHelper : base class is OWeakAggObject |
| <li> WeakAggComponentImplHelper : base class is OWeakAggObject, |
| implements the same stuff as OComponentHelper |
| </ul> |
| Add the number of interfaces, you wish to implement, to the helper name ( |
| something like va_arg for templates would be really cool). |
| The implementation helper have the disadvantage, that the code is not debugable (because |
| most of the code is implemented in macros), they have the advantage, that the error prone |
| queryInterface and XTypeProvider implementation are not done by every application developer |
| again and again (this saves really lots of debugging sessions). So using the implementation |
| helper is the proposed way to implement UNO-objects. |
| |
| <p> There are, nevertheless, situations where you can't use the implementation |
| helper (for example if you must implement more than 10 interfaces or if you |
| have to provide a more complex query interface).</p> |
| |
| <h4> Weak aggregation object </h4> |
| <p>Deriving from |
| <a href="../../ref/Cppuhelper/c_OWeakAggObject.html"><code>cppu::OWeakAggObject</code></a> |
| makes your object able to be |
| <a href="../../../common/man/concept/unointro.html#aggregation">aggregated</a>.</p> |
| |
| <h4> The propertyset helper</h4> |
| Use |
| <a href="../../ref/Cppuhelper/c_OPropertySetHelper.html"><code>::cppu::OPropertySetHelper |
| </code></a> |
| as base class, if you want to implement XPropertySet interface. [...] to be continued. |
| There is no implementation helper variant for OPropertySetHelper. |
| |
| <h4> The factory helper</h4> |
| The factory helpers allows to create factories for objects. |
| See <a href="#exported_symbols">exported symbols</a> for a use |
| case for them. |
| <br/> |
| <br/> |
| |
| <h2> <a NAME="contexts"></a>UNO contexts</h2> |
| |
| <h4><a name="component_context"></a> |
| Bootstrapping the initial component context (factory context) </h4> |
| |
| <p>The initial startup of the UNO system requires some sophisticated bootstrapping to |
| get an initial component context (including a service manager) to proceed service |
| instantiation. The context provides you a service manager instance.<br/> |
| The cppuhelper function below can be called to bootstrap an initial component context |
| with service manager upon a given registry. This includes insertion of initial the |
| following service factories: |
| <ul> |
| <li>(registry) service manager</li> |
| <li>shared lib loader</li> |
| <li>simple registry</li> |
| <li>nested registry</li> |
| <li>implementation registration</li> |
| <li>registry typedescription provider</li> |
| <li>typedescription manager</li> |
| </ul> |
| |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| cppuhelper/bootstrap.hxx: |
| |
| Reference< XComponentContext > SAL_CALL bootstrap_InitialComponentContext( |
| Reference< registry::XSimpleRegistry > const & xRegistry, |
| OUString <font color="red">const</font> & rBootstrapPath = OUString() ) |
| SAL_THROW( (Exception) ); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <br/> |
| The function reads out all <code>/SINGLETONS</code> entries out of the registry and inserts |
| entries into the component context. |
| The typedescription manager singleton is raised to deliver types to the cppu core typelib, too.<br/> |
| To handle registries in a flexible way, there are two helper functions to get a |
| simple registry and nested registry implementation: |
| <br/><br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| cppuhelper/bootstrap.hxx: |
| |
| Reference< registry::XSimpleRegistry > SAL_CALL createSimpleRegistry( |
| <font color="red">const</font> OUString & rBootstrapPath = OUString() ) |
| SAL_THROW( () ); |
| |
| Reference< registry::XSimpleRegistry > SAL_CALL createNestedRegistry( |
| <font color="red">const</font> OUString & rBootstrapPath = OUString() ) |
| SAL_THROW( () ); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <br/> |
| |
| There is also another function to bootstrap the UNO system reading reading out of environment |
| variables the way it is presented |
| <a href="xxxtodo_insert_default_boostrapping_description_here">here</a>. |
| |
| <br/><br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| cppuhelper/bootstrap.hxx: |
| |
| Reference< XComponentContext > SAL_CALL defaultBootstrap_InitialComponentContext() |
| SAL_THROW( (Exception) ); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <br/> |
| The context holds arbitrary values which are recommended to be prefixed by the implementation |
| name of the component that acknowledges a value, e.g. if you want to set the cache size |
| of the <code>stoc</code> typedescription manager, set: |
| <code>com.sun.star.comp.stoc.TypeDescriptionManager.CacheSize</code> to <i>n</i>. |
| All API singletons are directly accessible by their name.<br/> |
| When closing down the application, you have to manually dispose the component context, which |
| disposes all singleton objects including the service manager. |
| This has to be done, because |
| the context holds a hard reference to its service manager as well as the service manager |
| its default context (property <code>"DefaultContext"</code>). |
| By default each new component context wrapping an existing one (delegating unknown |
| property requests to it) should add itself as event listener to dispose itself |
| when the previous one is disposed (that is chaining). |
| <br/><br/> |
| Alternatively, you can call the existing functions in <code>servicefactory.hxx</code> |
| to bootstrap a service manager instance. |
| But when closing down, it is mandatory to dispose the component context |
| (service manager's <code>"DefaultContext"</code> property).<br/> |
| <br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| <font color="green"> // get initial context</font> |
| Reference< XComponentContext > xContext( defaultBootstrap_InitialComponentContext() ); |
| OSL_ASSERT( xContext.is() ); |
| |
| <font color="green"> // retrieve typedescription manager singleton</font> |
| Reference< XHierarchicalNameAccess > xTDMgr; |
| OSL_VERIFY( xContext->getValueByName( OUString( RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.reflection.TypeDescriptionManager") ) ) >>= xTDMgr ); |
| |
| <font color="green"> // easier: retrieve service manager singleton</font> |
| Reference< XMultiComponentFactory > xSMgr( xContext->getServiceManager() ); |
| <font color="green"> /* same as: |
| Reference< XMultiComponentFactory > xSMgr; |
| OSL_VERIFY( xContext->getValueByName( OUString( RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.lang.ServiceManager") ) ) >>= xSMgr ); |
| */ |
| |
| // launch new typedescription manager instance with modified cache size, |
| // NOTICE: knowing the context cache size key is implementation detail |
| // of the raised component. Caching is no concept of the implementation |
| // and can thus be ignored by the implementation! |
| |
| // look at cppuhelper/component_context.hxx:</font> |
| Contextentry_Init aEntry; |
| aEntry.bLateInitService = false; |
| aEntry.name = OUString( RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.comp.stoc.TypeDescriptionManager.CacheSize") ); |
| aEntry.value = makeAny( (sal_Int32)0xdb0 ); |
| <font color="green"> // create new context overriding cache size, rest is delegated to previous context</font> |
| Reference< XComponentContext > xNewContext( createComponentContext( |
| &aEntry, 1, xContext ); |
| Reference< XInterface > xNewTDMgr( xSMgr->createInstanceWithContext( |
| OUString( RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.reflection.TypeDescriptionManager") ), xNewContext ) ); |
| |
| ... |
| |
| Reference< XComponent > xComp( xContext, UNO_QUERY ); |
| OSL_ASSERT( xComp.is() ); |
| xComp->dispose(); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| <br/> |
| |
| <h4><a name="current_context"></a> Setting/ Retrieving the Current Context </h4> |
| |
| The <a href="../../../common/man/concept/uno_contexts.html#current_context">current (task/ thread) context</a> |
| has to be manually set when launching a new thread. |
| There is a pair of functions setting and getting the context in <code>uno/current_context.h</code> |
| and <code>uno/current_context.hxx</code>:<br/><br/> |
| |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| uno/current_context.h: |
| |
| sal_Bool SAL_CALL uno_getCurrentContext( |
| <font color="red"> void</font> ** ppCurrentContext, |
| rtl_uString * pEnvTypeName, void * pEnvContext ) |
| SAL_THROW_EXTERN_C(); |
| |
| sal_Bool SAL_CALL uno_setCurrentContext( |
| <font color="red"> void</font> * pCurrentContext, |
| rtl_uString * pEnvTypeName, void * pEnvContext ) |
| SAL_THROW_EXTERN_C(); |
| |
| |
| uno/current_context.hxx: |
| |
| <font color="red">namespace</font> com { <font color="red">namespace</font> sun { <font color="red">namespace</font> star { <font color="red">namespace</font> uno { |
| |
| inline Reference< XCurrentContext > SAL_CALL getCurrentContext() |
| SAL_THROW( () ); |
| inline bool SAL_CALL setCurrentContext( Reference< XCurrentContext > const & xContext ) |
| SAL_THROW( () ); |
| |
| } } } } |
| |
| |
| IDL interface: |
| |
| module com { module sun { module star { module uno { |
| |
| interface XCurrentContext : com::sun::star::uno::XInterface |
| { |
| any getValueByName( [in] string Name ); |
| }; |
| |
| }; }; }; }; |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <br/> |
| |
| The first pair of functions is independent of the callers UNO environment while the second |
| is defining inline functions for a C++ caller (more convenient). |
| You should take care with what is handled in this thread/task-local container. |
| <br/> |
| <br/> |
| |
| |
| <!-- *************************************** |
| * Components |
| *************************************** --> |
| <h2> <a NAME="components"></a>C++ components</h2> |
| C++ components are implemented in shared libraries (or modules in OpenOffice.org). The implementation |
| of a sample component is documented <a href="../component_tutorial.html">here</a>. |
| Each module must |
| support some C-symbols, which the shared-library-loader uses as entry points to access |
| the components. |
| |
| <h4><a name="exported_symbols"></a> Exported symbols </h4> |
| <p>Each module must export 4 C functions to make the |
| components available.</p> |
| <p>TODO: List the header files required to export these symbols</p> |
| |
| <ol> |
| <li>component_getImplementationEnvironmentFunc<br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| /************************************************************** |
| * Function to determine the environment of the implementation. |
| * If the environment is NOT session specific |
| * (needs no additional context), then this function |
| * should return the environment type name and leave ppEnv (0). |
| * |
| * @param ppEnvTypeName environment type name; |
| * string must be constant |
| * @param ppEnv function returns its environment |
| * if the environment is session specific, |
| * i.e. has special context |
| */ |
| typedef void |
| (SAL_CALL * component_getImplementationEnvironmentFunc)( |
| const sal_Char ** ppEnvTypeName,uno_Environment ** ppEnv); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| The loader uses this function to determine the native environment of the component. |
| In general, the component simply returns the compiler environment name. This enables us |
| to use modules compiled by different compilers in the same process, assuming that |
| a C++ to UNO bridge exists for each compiler. |
| |
| <li>component_getDescriptionFunc<br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| /************************************************************ |
| * Optional function to retrieve a component description. |
| * |
| * @return an XML formatted string containing a short |
| * component description |
| */ |
| typedef const sal_Char * |
| (SAL_CALL * component_getDescriptionFunc)(void); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| The function must return a string that contains the XML-description of the component. This |
| allows generic tools (testtools, implementation repository browsers, etc.) to collect |
| information about the module. |
| |
| <li>component_writeInfoFunc<br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| /********************************************************** |
| * Writes component registry info, at least writing the |
| * supported service names. |
| * |
| * @param pServiceManager a service manager |
| * (the type is XMultiServiceFactory |
| * to be used by the environment |
| * returned by |
| * component_getImplementationEnvironment) |
| * @param pRegistryKey a registry key |
| * (the type is XRegistryKey to be used |
| * by the environment returned by |
| * component_getImplementationEnvironment) |
| * @return true if everything went fine |
| */ |
| typedef sal_Bool (SAL_CALL * component_writeInfoFunc)( |
| void * pServiceManager, void * pRegistryKey ); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| This function is called by the service <em>com.sun.star.registry.ImplementationRegistration</em>. |
| It passes an XMultiServiceFactory and an XRegistryKey interface pointer, which are already |
| mapped into the modules environment. The function can now register all implementations and |
| services into this registry key. |
| |
| <li>component_getFactoryFunc<br/> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| /********************************************************* |
| * Retrieves a factory to create component instances. |
| * |
| * @param pImplName desired implementation name |
| * @param pServiceManager a service manager |
| * (the type is XMultiServiceFactory |
| * to be used by the environment |
| * returned by |
| * component_getImplementationEnvironment) |
| * @param pRegistryKey a registry key |
| * (the type is XRegistryKey to be used |
| * by the environment returned by |
| * component_getImplementationEnvironment) |
| * @return acquired component factory |
| * (the type is XInterface to be used by the |
| * environment returned by |
| * component_getImplementationEnvironment) |
| */ |
| typedef void * (SAL_CALL * component_getFactoryFunc)( |
| const sal_Char * pImplName, |
| void * pServiceManager, void * pRegistryKey ); |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>This function is usually called the first time a component needs to be |
| instantiated. The function should return an acquired XInterface |
| interface-pointer for the requested implementation name.</p> |
| </ol> |
| |
| <p>Example (the implementation of the service is not shown here):</p> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| |
| #define IMPLEMENTATION_NAME "com.sun.star.comp.io.stm.Pipe" |
| const sal_Char SERVICE_NAME[] = "com.sun.star.io.Pipe"; |
| Sequence< OUString > pipe_getSupportedServiceNames() |
| { |
| Sequence< OUString > seqNames(1); |
| seqNames.getArray()[0] = |
| OUString::createFromAscii( SERVICE_NAME ); |
| return seqNames; |
| } |
| |
| Reference< XInterface > SAL_CALL pipe_CreateInstance( |
| const Reference< XComponentContext > & xContext ) |
| { |
| return Reference < XInterface >( |
| ( OWeakObject * ) new OPipe(xContext) ); |
| } |
| |
| |
| extern "C" |
| { |
| |
| void SAL_CALL component_getImplementationEnvironment( |
| const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv ) |
| { |
| *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; |
| } |
| //================================================================== |
| sal_Bool SAL_CALL component_writeInfo( |
| void * pServiceManager, void * pRegistryKey ) |
| { |
| if (pRegistryKey) |
| { |
| Reference< XRegistryKey > xNewKey( |
| reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( |
| OUString::createFromAscii( |
| "/" IMPLEMENTATION_NAME "/UNO/SERVICES" ) ) ); |
| |
| const Sequence< OUString > & rSNL = pipe_getSupportedServiceNames(); |
| const OUString * pArray = rSNL.getConstArray(); |
| for ( sal_Int32 nPos = rSNL.getLength(); nPos--; ) |
| xNewKey->createKey( pArray[nPos] ); |
| |
| return sal_True; |
| } |
| return sal_False; |
| } |
| //=================================================================== |
| void * SAL_CALL component_getFactory( |
| const sal_Char * pImplName, |
| void * pServiceManager, void * pRegistryKey ) |
| { |
| void * pRet = 0; |
| |
| if (pServiceManager && |
| rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0) |
| { |
| Reference< XSingleComponentFactory > xFactory( createSingleComponentFactory( |
| reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), |
| OUString::createFromAscii( IMPLEMENTATION_NAME ), |
| pipe_CreateInstance, pipe_getSupportedServiceNames() ) ); |
| |
| if (xFactory.is()) |
| { |
| xFactory->acquire(); |
| pRet = xFactory.get(); |
| } |
| } |
| |
| return pRet; |
| } |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>TODO: This is quite a lot of code. Let's roughly step through it. [...] |
| |
| |
| <h4> Singletons / MultiInstance </h4> |
| <p> |
| Every component has to be implemented as multi-instance, i.e. upon loading the library |
| they can use the cppuhelper <code>createSingleComponentFactory()</code> as outlined |
| above. |
| The old functions <code>createSingleFactory()</code> etc. are deprecated and should |
| be changed. |
| One-instance components (using <code>createOneInstanceFactory</code>) are deprecated, too. |
| The component implementation should not decide by itself whether it is one-instance. |
| Instead of this, a component should explicitly retrieve shared objects (singletons) via its |
| context. All singleton key name (context key names) are to specified in IDL, |
| for example: |
| </p> |
| <table width="100%" bgcolor="#ffffc0"> |
| <tr> |
| <td> |
| <pre> |
| module com { module sun { module star { module reflection { |
| |
| singleton TypeDescriptionManager |
| { |
| service com::sun::star::reflection::TypeDescriptionManager; |
| }; |
| |
| }; }; }; }; |
| </pre> |
| </td> |
| </tr> |
| </table> |
| |
| <h4> Independent components </h4> |
| A component is called independent if it is only linked against UDK libraries. The aim is |
| to have an application that only uses independent components. The only external thing they |
| need is a service manager to instantiate other components. |
| |
| <h4> Component registration </h4> |
| In general, every application has a registry (in OpenOffice, |
| it is called <em> applicat.rdb </em>). The applicat.rdb contains the definition of all types |
| used in the application and information how to instantiate a |
| component. This information is written into the rdb by the component itself using |
| the above <code>component_writeInfo</code> function. |
| |
| <p> The service <code> com.sun.star.registry.ImplementationRegistration</code> |
| can be used to register a shared library. The service exports the interface |
| |
| <a href="http://api.openoffice.org/common/ref/com/sun/star/registry/XImplementationRegistration.html"> |
| <code>com.sun.star.registry.XImplementationRegistration</code></a>, which offers |
| the registerImplementation-method. The library name, the |
| service name of the loader (in general <code>com.sun.star.loader.SharedLibrary</code>) and |
| a reference to a XRegistryKey interface (where the data shall be written to) must all be passed to the method. |
| If an empty reference is passed, the service uses the registry of the servicemanager. |
| |
| <p> There exists a command line tool for registration (<code>regcomp</code>), that does |
| this (just call the tool without parameters to see its usage). |
| |
| <p> After the registration, the service is accessible directly through the servicemanager. |
| |
| <p> Note that if you have created new UNO-types in IDL, the types must also be merged into the |
| applications registry (use the <code>regmerge</code> tool for this purpose). |
| |
| <!-- *************************************** |
| * Common programming patterns |
| *************************************** --> |
| <h2><a NAME="common_patterns"></a>Common programming patterns</h2> |
| |
| <ul> |
| <li> Threads and members<br/> |
| <p>Access to members in unguarded sections are in general not thread |
| safe. Thus the following code and may crash (where m_xFoo is a |
| reference to an UNO object).</p> |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| NOT THREAD SAFE : |
| MyComponent::do() |
| { |
| if( m_xFoo.is() ) |
| m_xFoo->doSomething(); |
| } |
| |
| THREAD SAFE : |
| MyComponent::do() |
| { |
| Reference < XFoo > xFoo; |
| { |
| MutexGuard guard( m_mutex ); |
| xFoo = m_xFoo; |
| } |
| if( xFoo.is() ) |
| xFoo->doSomething(); |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>Between the check of m_xFoo.is() and the call m_xFoo->doSomething(), |
| the reference may be cleared by another thread or during the call of |
| m_xFoo->doSomething() may be cleared, which can lead to the destruction |
| of the UNO-object.</p> |
| <p> |
| The reference assignment is not thread safe, as it is not an atomic operation |
| (the reference might be cleared by another thread, before the current thread reaches |
| the osl_incrementInterlockedCount() function). Therefor each member access must be guarded. |
| <p> |
| Note that this holds also for other refcounted objects such as strings, sequences, etc. |
| <p> |
| This certainly implies performance overhead of locking a mutex. If you |
| know, that a certain member can never be changed, it is correct not to guard access |
| to this member. But keep in mind that your code should also be stable to small modifications. |
| If you don't need the performance in that piece of code, you should always |
| choose the safer method. |
| Code must be in first place correct and in second place fast. |
| |
| <li> Initialize static objects on demand <br/> |
| <p>If there is need for a static object, do not initialize it before main. |
| This is a serious performance hit at application startup. Use wrapper |
| functions to access static data instead, so that they are initialized on |
| demand.</p> |
| |
| <li> Thread safe initializing static data <br/> |
| <p>Initialization of non atomic static data, that is not initialized before |
| main (see above) must be guarded. To make this efficient, do the |
| following.</p> |
| |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=4> |
| <tr> |
| <td BGCOLOR="#FFFFC0"> |
| <pre> |
| Mutex * getInitMutex() |
| { |
| <font color="red"> static </font>Mutex *pInitMutex = 0; |
| if( ! pInitMutex ) |
| { |
| ::osl::Guard guard( ::osl::Mutex::getGlobalMutex() ); |
| if( ! pInitMutex ) |
| { |
| <font color="red">static</font> ::osl::Mutex initMutex; |
| pInitMutex = &initMutex; |
| } |
| } |
| <font color="red"> return</font> pInitMutex; |
| } |
| |
| |
| MyStaticData *getMyStaticDataImpl() |
| { |
| <font color="red"> static</font> MyStaticData staticData; |
| return &staticData; |
| } |
| |
| <font color="red">static</font> g_pMyStaticData * =0; |
| inline MyStaticData *getMyStaticData() |
| { |
| if( ! g_pMyStaticData ) |
| { |
| ::osl::Guard guard( getInitMutex() ); |
| if( ! g_pMyStaticData ) |
| { |
| g_pMyStaticData = getMyStaticDataImpl(); |
| } |
| } |
| <font color="red">return</font> g_pMyStaticData; |
| } |
| </pre> |
| </td> |
| </tr> |
| </table> |
| <p>This looks a bit more complicated than it really is, lets step through it. The aim is to retrieve |
| a pointer to the static data (here MyStaticData) as fast as possible (the first access can |
| be slower, because these are only one time costs), so getMyStaticData is |
| inline. If the data has been initialized before, then access is very fast (in fact a check to |
| zero overhead, no function call).</p> |
| |
| <p>The construction of the static data should not be an inline function, |
| because the current |
| version of gcc on the Mac has problems with static data in inline functions. |
| |
| <p> The mutex used to guard the initialization is also constructed in this |
| example. The construction of the mutex is guarded by the ::osl::Mutex::getGlobalMutex(), |
| one of the rare objects constructed before main. |
| Why not use the global mutex directly for guarding ? The answer is that it can be done, if |
| and ONLY if the constructor of MyStaticData does not call something you do not know. If |
| the constructor does a UNO-call, which is bridged to another process, the reply for this |
| call is dispatched in a different thread and this thread needs to initialize some static data |
| of its own, then you have a deadlock (too many debugging sessions have been spent on this...!) |
| |
| <li> <p>DON'T USE MACROS </p> |
| <p>There are a lot of different opinions on this topic, but I want to stress this topic |
| here : Do not use macros if there are other solutions (inline functions, |
| inline template functions, const vars, etc.). |
| |
| Using macros generally has the following drawbacks:</p> |
| <ul> |
| <li> It is not type safe. The compiler does fewer checks, which results in finding |
| bugs at runtime instead of finding them at compile time. |
| <li> The debugger does not know the symbols (e.g. strings, constants). |
| <li> If code is executed within macros, it is not debuggable. |
| <li> The code gets very difficult to read. |
| </ul> |
| <p><b>Code is read much more often read than it is written.</b></p> |
| </ul> |
| |
| <!-- **************************************** |
| * Footer |
| **************************************** --> |
| <table width=100%> |
| <tr> |
| <td BGCOLOR="#666699"><font color="#FFFFFF">Author: <a href="mailto:joerg.budischewski@germany.sun.com"><font color=#ffffff>Joerg |
| Budischewski</font></a> ($Date: 2004/11/17 11:04:33 $) |
| <br/><I>Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA.</I></font></td> |
| </tr> |
| </table> |
| </body> |
| </html> |