Documentation/DevGuide/Advanced UNO

Choosing an Implementation Language
The UNO technology provides a framework for cross-platform and language independent programming. All the LibreOffice components can be implemented in any language supported by UNO, as long as they only communicate with other components through their IDL interfaces.

A developer can customize the office to their needs with this flexibility, but they will have to decide which implementation language should be selected for a specific problem.

Supported Programming Environments
The support for programming languages in UNO and LibreOffice is divided into three different categories.

The following table lists programming languages currently supported by UNO. 'Yes' in the table columns denotes full support, 'no' denotes that there is no support and is not even planned in the future. 'Maybe in future' means there is currently no support, but this may change with future releases.
 * 1) Languages that invoke calls on existing UNO objects are possibly implemented in other programming languages. Additionally, it may be possible to implement certain UNO interfaces, but not UNO components that can be instantiated by the service manager.
 * 2) Languages that implement UNO components. UNO objects implemented in such a language are accessible from any other language that UNO supports, just by instantiating a service by name at the servicemanager. For instance, the developer can implement a LibreOffice Calc addin (see Spreadsheet Documents).
 * 3) Languages that are used to write code to be delivered within LibreOffice documents and utilize dialogs designed with the LibreOffice dialog editor.

Java
Java is a an accepted programming language offering a standard library with a large set of features and available extensions. Additional extensions will be available in the future, such as JAX-RPC for calling webservices. It is a typesafe language with a typesafe UNO binding. Although interfaces have to be queried explicitly, the type safety makes it suitable for larger projects. UNO components can be implemented with Java, that is, the Java VM is started on demand inside the office process when a Java component is instantiated. The OfficeBean allows embedding LibreOffice documents in Java Applets and Applications.

There is a constant runtime overhead of about 1 to 2 ms per call that is caused by the bridge conversion routines when calling UNO objects implemented in other language bindings. Since LibreOffice consists of C++ code, every Java call into the office needs to be bridged. This poses no problems if there are a few calls per user interaction. The runtime overhead will hurt the application when routines produce hundreds or thousands of calls.

C++
C++ is an accepted programming language offering third-party products. In addition to C++ being fast since it is compiled locally, it offers the fastest communication with LibreOffice because most of the essential parts of office have been developed in C++. This advantage becomes less important as you call into the office through the interprocess bridge, because every remote call means a constant loss of 1 to 2 ms. The fastest code to extend the office can be implemented as a C++ UNO component. It is appropriate for larger projects due to its strong type safety at compile time.

C++ is difficult to learn and coding, in general, takes longer, for example, in Java. The components must be built for every platform, that leads to a higher level of complexity during development and deployment.

LibreOffice Basic
LibreOffice Basic is the scripting language developed for and integrated directly into LibreOffice. It currently offers the best integration with LibreOffice, because you can insert code into documents, attach arbitrary office events, such as document loading, keyboard shortcuts or menu entries, to Basic code and use dialogs designed within the LibreOffice IDE. In Basic, calls are invoked on an object rather than on a specific interface. Interfaces, such as com.sun.star.beans.XPropertySet are integrated as Basic object properties. Basic always runs in the office process and thus avoids costly interprocess calls.

The language is type unsafe, that is, only a minimal number of errors are found during compilation. Most errors appear at runtime, therefore it is not the best choice for large projects. The language is LibreOffice specific and only offers a small set of runtime functionality with little third-party support. All office functionality is used through UNO. UNO components cannot be implemented with Basic. The only UNO objects that can be implemented are listeners. Finally, Basic does not offer any thread support.

OLE Automation Bridge
The OLE Automation bridge opens the UNO world to programming environments that support OLE automation, such as Visual Basic, JScript, Delphi or C++ Builder. Programmers working on the Windows platform can write programs for LibreOffice without leaving their language by learning a new API. These programmers have access to the libraries provided by their language. It is possible to implement UNO objects, if the programming language supports object implementation.

This bridge is only useful on a Win32 machine, thereby being a disadvantage. Scripts always run in a different process so that every UNO call has at least the usual interprocess overhead of 1 to 2 ms. Currently Automation UNO components cannot be implemented for the service manager, but this may change in the future.

Python
A Python scripting bridge (PyUNO) is currently developed by Ralph Thomas. It is available in an experimental alpha state with known limitations. For details, see PyUNO on www.openoffice.org/udk/.

Use Cases
The following list gives typical UNO applications for the various language environments.

Java

 * Servlets creating Office Documents on the fly, Java Server Pages
 * Server-Based Collaboration Platforms, Document Management Systems
 * Calc add-ins
 * Chart add-ins
 * Database Drivers

C++

 * Filters reading document data and generating Office Documents through UNO calls
 * Database Drivers
 * Calc add-ins
 * Chart add-ins

LibreOffice Basic

 * Office Automation
 * Event-driven data-aware forms

OLE Automation

 * Office Automation, creating and controlling Office Documents from other applications and from Active Server Pages

Python

 * Calc add-ins

Recommendation
All languages have their advantages and disadvantages as previously discussed, but there is not one language for all purposes, depending on your use. Consider carefully before starting a new project and evaluate the language to use so that it saves you time.

Sometimes it may be useful to use multiple languages to gain the advantages of both languages. For instance, currently it is not possible to attach a keyboard event to a Java method, therefore, write a small Basic function, which forwards the event to a Java component.

The number of languages supported by UNO may increase and some limitations shown in the table above may disappear.

Language Bindings
UNO language bindings enable developers to use and implement UNO objects in arbitrary programming languages. Thus, the existing language bindings connect between implementation environments, such as Java, C++, LibreOffice Basic and OLE Automation. The connection is accomplished by bridges. The following terms are used in our discussion about the implementation of language bindings.

In our context, the target language or target environment denotes the language or environment from which the UNO component model is accessed. The bridging language is the language used for writing the bridge code.

An object-oriented language determines the layout of its objects in memory. We call an object that is based on this layout a language object. The layout along with everything that relates to it, such as creation, destruction, and interaction, is the object model of a language.

A UNO proxy (short: proxy) is created by a bridge and it is a language object that represents a UNO object in the target language. It provides the same functionality as the original UNO object. There are two terms which further specialize a UNO proxy. The UNO interface proxy is a UNO proxy representing exactly one interface of a UNO object, whereas a UNO object proxy represents an uno object with all its interfaces.

An interface bridge bridges one UNO interface to one interface of the target language, that is, to a UNO interface proxy. When the proxy is queried for another interface that is implemented by the UNO object, then another interface proxy is returned. In contrast, an object bridge bridges entire UNO objects into UNO object proxies of the target language. The object proxy receives calls for all interfaces of the UNO object.

Implementing UNO Language Bindings
This section introduces the basic steps to create a new language binding. The steps required depend on the target language. The section provides an overview of existing language bindings to help you to decide what is necessary for your case. It is recommended that you read the sources for available language bindings and transfer the solutions they offer to the new circumstances of your target language.

Overview of Language Bindings and Bridges
Creating a language binding for UNO involves the following tasks:

Language Specification and UNO Feature Support
When writing a language binding, consider how to map UNOIDL types to your target language, treat simple types and handle complex types, such as,  ,   and. Furthermore, UNOIDL features, such as services, properties and exceptions must be matched to the capabilities of the target language and accommodated, if need be.

Code Generator
If the target language requires type definitions at compile time, a code generator must translate UNOIDL type definitions to the target language type definitions according to the language specification, so that the types defined in UNOIDL can be used.

UNO Bridge
UNO communication is based on calls to interfaces. Bridges supply the necessary means to use interfaces of UNO objects between implementation environments. The key for bridging is an intermediate environment called binary UNO,that consists of binary data formats for parameters and return values, and a C dispatch method used to call arbitrary operations on UNO interfaces. A bridge must be capable of the following tasks:

The Reflection API delivers information about UNO types and is used by bridges to support type conversions ( com.sun.star.script.Converter ), and method invocations ( com.sun.star.script.Invocation and com.sun.star.script.XInvocation ). Furthermore, it supplies runtime type information and creates instances of certain UNO types, such as structs ( com.sun.star.reflection.CoreReflection ).
 * Between the target language and LibreOffice:
 * Converting operation parameters from the target language to binary UNO.
 * Transforming operation calls in the target language to calls in binary UNO in a different environment.
 * Transporting the operation call with its parameters to LibreOffice and the return values back to the target language.
 * Mapping return values from binary UNO to the target language.
 * Between LibreOffice and the target language, that is, during callbacks or when using a component in the target language:
 * Converting operation parameters from binary UNO to the target language.
 * Transforming operation calls in binary UNO to calls in the target language.
 * Transporting the operation call with its parameters to the target language and the return values back to LibreOffice.
 * Converting return values from the target language to binary UNO.

UNO Component Loader
An implementation loader is required to load and activate code produced by the target language if implementations in the target language are to be instantiated. This involves locating the component files produced by the target language, and mechanisms to load and execute the code produced by the target language, such as launching a runtime environment. Currently, there are implementation loaders for jar files and locally shared libraries on the platforms supported by UNO.

Bootstrapping
A UNO language binding must prepare itself so that it can bridge to the UNO environments. It depends on the target environment how this is achieved. In Java, C++, and Python, a local service manager in the target environment is used to instantiate a com.sun.star.bridge.UnoUrlResolver that connects to LibreOffice. In the Automation bridge, the object  is obtained from the COM runtime system and in LibreOffice Basic the service manager is available from a special method of the Basic runtime environment,.

Implementation Options
There are two different approaches when creating a UNO language binding.


 * 1) Programming languages checking types at compile time. Examples are the languages Java or C++. In these environments, it is necessary to query for interfaces at certain objects and then invoke calls compile-time-typesafe on these interfaces.
 * 2) Programming languages checking types at runtime. Examples are the languages StarBasic, Python or Perl. In these languages, the interfaces are not queried explicitly as there is no compiler to check the signature of a certain method. Instead, methods are directly invoked on objects. During execution, the runtime engine checks if a method is available at one of the exported interfaces, and if not, a runtime error is raised. Typically, such a binding has a slight performance disadvantage compared to the solution above.

You can achieve different levels of integration with both types of language binding.


 * 1) Call existing UNO interfaces implemented in different bindings. This is the normal scripting use case, for example, connect to a remote running office, instantiate some services and invoke calls on these services (unidirectional binding).
 * 2) Implement UNO interfaces and let them be called from different bindings.In addition to 1) above, a language binding is able to implement UNO interfaces, for example, for instance listener interfaces, so that your code is notified of certain events (limited bidirectional binding).
 * 3) Implement a UNO component that is instantiated on demand from any other language at the global service manager. In addition to 2) above, a binding must provide the code which starts up the runtime engine of the target environment. For example, when a Java UNO component is instantiated by the LibreOffice process, the Java VM must be loaded and initialized, before the actual component is loaded (bidirectional binding).

A language binding should always be bidirectional. That is, it should be possible to access UNO components implemented in the target language from LibreOffice, as well as accessing UNO components that are implemented in a different language from the target language.

The following table provides an overview about the capabilities of the different language bindings currently available for LibreOffice:

The next section outlines the implementation of a C++ language binding. The C++ binding itself is extremely platform and compiler dependent, which provides a barrier when porting LibreOffice to a new platform. Although this chapter focuses on C++ topics, the chapter can be applied for other typesafe languages that store their code in a shared library, for instance, Delphi, because the same concepts apply.

The section UNO Reflection API considers the UNO reflection and invocation API, which offers generic functionality to inspect and call UNO objects. The section XInvocation Bridge explains how the Reflection API is used to implement a runtime type-checking language binding.

The final chapter Implementation Loader briefly describes the concept of implementation loaders that instantiates components on demand independently of the client and the implementation language. The integration of a new programming language into the UNO component framework is completed once you have a loader.

UNO C++ Bridges
This chapter focuses on writing a UNO bridge locally, specifically writing a C++ UNO bridge to connect to code compiled with the C++ compiler. This is an introduction for bridge implementers.. It is assumed that the reader has a general understanding of compilers and a of 80x86 assembly language. Refer to the section Implementation Loader for additional information.

Binary UNO Interfaces
A primary goal when using a new compiler is to adjust the C++-UNO data type generator (cppumaker tool) to produce binary compatible declarations for the target language. The tested cppu core functions can be used when there are similar sizes and alignment of UNO data types. The layout of C++ data types, as well as implementing C++-UNO objects is explained in C++ Language Binding.

When writing C++ UNO objects, you are implementing UNO interfaces by inheriting from pure virtual C++ classes, that is, the generated cppumaker classes (see .hdl files). When you provide an interface, you are providing a pure virtual class pointer. The following paragraph describes how the memory layout of a C++ object looks.

A C++-UNO interface pointer is always a pointer to a virtual function table (vftable), that is, a C++ this pointer. The equivalent binary UNO interface is a pointer to a struct  that contains function pointers. This struct holds a function pointer to a  and also a function pointer to   and  :

Similar to com.sun.star.uno.XInterface, the life-cycle of an interface is controlled using the  and   functions of the binary UNO interface. Any other method is called through the dispatch function pointer. The dispatch function expects the binary UNO interface pointer, the interface member type of the function to be called, an optional pointer for a return value, the argument list and finally a pointer to signal an exception has occurred.

The caller of the dispatch function provides memory for the return value and the exception holder.

The pArgs array provides pointers to binary UNO values, for example, a pointer to an interface reference or a pointer to a SAL 32 bit integer.

A bridge to binary UNO maps interfaces from C++ to binary UNO and conversely. To achieve this, implement a mechanism to produce proxy interfaces for both ends of the bridge.

C++ Proxy
A C++ interface proxy carries its interface type (reflection), as well as its destination binary UNO interface ( pointer). The proxy's vftable pointer is patched to a generated vftable that is capable of determining the index that was called ,as well as the this pointer of the proxy object to get the interface type.

The vftable requires an assembly code. The rest is programmed in C/C++. You are not allowed to trash the registers. On many compilers, the this pointer and parameters are provided through stack space. The following provides an example of a Visual C++ 80x86:

The vftable is filled with pointers to the different slot code (snippets). The snippet code recognizes the table index being called and calls. That function calls a C/C++ function and sets output registers upon return, for example, for floating point numbers depending on the return value type.

Remember that the vftable handling described above follows the Microsoft calling convention, that is, the this pointer is always the first parameter on the stack. This is currently not the case for gcc that prepends a pointer to a complex return value before the this pointer on the stack if a method returns a struct. This complicates the (static) vftable treatment, because different vftable slots have to be generated for different interface types, adjusting the offset to the proxy this pointer:

This is usually the hardest part for stack-oriented compilers. Afterwards proceed in C/C++ to examine the proxy interface type, read out parameters from the stack and prepare the call on the binary UNO destination interface.

Each parameter is read from the stack and converted into binary UNO. Use cppu core functions if you have adjusted the cppumaker code generation (alignment, sizes) to the binary UNO layout (see cppu/inc/uno/data.h).

After calling the destination  method, convert any out/inout and return the values back to C++-UNO, and return to the caller. If an exception is signalled, throw the exception provided to you in. In most cases, you can utilize Runtime Type Information (RTTI) from your compiler framework to throw exceptions in a generic manner. Disassemble code throwing a C++ exception, and observe what the compiler generates.

Binary UNO Proxy
The proxy code is simple for binary UNO. Convert any /  parameters to C++-UNO values, preparing a call stack. Then perform a virtual function call that is similar to the following example for Microsoft Visual C++:

First stack data is pushed to the stack., including a  pointer, then the virtual function's pointer is retrieved and called. When the call returns, the return register values are copied back. It is also necessary to catch all exceptions generically and retrieve information about type and data of a thrown exception. In this case, look at your compiler framework functions also.

Additional Hints
Every local bridge is different, because of the compiler framework and code generation and register allocation. Before starting, look at your existing bridge code for the processor, compiler, and the platform in module bridges/source/cpp_uno that is part of the LibreOffice source tree on www.openoffice.org.

Also test your bridge code extensively and build the module cppu with debug symbols before implementing the bridge, because cppu contains alignment and size tests for the compiler.

For quick development, use the executable build in cppu/test raising your bridge library, doing lots of calls with all kinds of data on mapped interfaces.

Also test your bridge in a non-debug build. Often, bugs in assembly code only occur in non-debug versions, because of trashed registers. In most cases, optimized code allocates or uses more processor registers than non-optimized (debug) code.

UNO Reflection API
This section describes the UNO Reflection API. This API includes services and interfaces that can be used to get information about interfaces and objects at runtime.

XTypeProvider Interface
The interface com.sun.star.lang.XTypeProvider allows the developer to retrieve all types provided by an object. These types are usually interface types and the  interface can be used at runtime to detect which interfaces are supported by an object. This interface should be supported by every object to make it scriptable from LibreOffice Basic.

Converter Service
The service com.sun.star.script.Converter supporting the interface com.sun.star.script.XTypeConverter provides basic functionality that is important in the reflection context. It converts values to a particular type. For the method com.sun.star.script.XTypeConverter:convertTo, the target type is specified as type, allowing any type available in the UNO type system. The method com.sun.star.script.XTypeConverter:convertToSimpleType converts a value into a simple type that is specified by the corresponding com.sun.star.uno.TypeClass. If the requested conversion is not feasible, both methods throw a com.sun.star.script.CannotConvertException.

CoreReflection Service
The service com.sun.star.reflection.CoreReflection supporting the interface com.sun.star.reflection.XIdlReflection is an important entry point for the Uno Reflection API. The  interface has two methods that each return a com.sun.star.reflection.XIdlClass interface for a given name (method  ) or any value (method getType).

The interface  is one of the central interfaces of the Reflection API. It provides information about types, especially about class or interface, and struct types. Besides general information, for example, to check type identity through the method  or to determine a type or class name by means of the method , it is possible to ask for the fields or members, and methods supported by an interface type (method   returning a sequence of   interfaces and method   returning a sequence of   interfaces).

The interface  is deprecated and should not be used. Instead the interface com.sun.star.reflection.XIdlField2 is available by querying it from an  interface returned by an   method.

The interface  or   represents a struct member of a struct or get or set accessor methods of an interface type. It provides information about the field (methods  and  ) and reads and - if allowed by the access mode - modifies its value for a given instance of the corresponding type (methods   and  ).

The interface  represents a method of an interface type. It provides information about the method (methods,  ,  ,   and  ) and invokes the method for a given instance of the corresponding type (method  ).

Introspection
The service com.sun.star.beans.Introspection supporting the interface com.sun.star.beans.XIntrospection is used to inspect an object of interface or struct type to obtain information about its members and methods. Unlike the  service, and the   interface ,the inspection is not limited to one interface type but to all interfaces supported by an object. To detect the interfaces supported by an object, the Introspection service queries for the  interface. If an object does not support this interface, the introspection does not work correctly.

To inspect an object, pass it as an any value to the  method of. The result of the introspection process is returned as com.sun.star.beans.XIntrospectionAccess interface. This interface is used to obtain information about the inspected object. All information returned refers to the complete object as a combination of several interfaces. When accessing an object through, it is impossible to distinguish between the different interfaces.

The com.sun.star.beans.XIntrospectionAccess interface provides a list of all properties (method getProperties) and methods (method ) supported by the object. The introspection maps methods matching the pattern

FooType getFoo setFoo(FooType)

to a property  of type.

com.sun.star.beans.XIntrospectionAccess also supports a categorization of properties and methods. For instance, it is possible to exclude "dangerous" methods, such as the reference counting methods com.sun.star.uno.XInterface:acquire and com.sun.star.uno.XInterface:release  from the set of methods returned by. When the Introspection service is used to bind a new scripting language, it is useful to block the access to functionality that could crash the entire LibreOffice application when used in an incorrect manner.

The  interface does not allow the developer to invoke methods and access properties directly. To invoke methods, the invoke method of the  interfaces returned by the methods   and   are used. To access properties, a com.sun.star.beans.XPropertySet interface is used that can be queried from the com.sun.star.beans.XIntrospectionAccess:queryAdapter method. This method also provides adapter interfaces for other generic access interfaces like com.sun.star.container.XNameAccess and com.sun.star.container.XIndexAccess, if these interfaces are also supported by the original object.

Invocation
The service com.sun.star.script.Invocation supporting the interface com.sun.star.lang.XSingleServiceFactory provides a generic, high-level access (higher compared to the  service) to the properties and methods of an object. The object that should be accessed through  is passed to the com.sun.star.lang.XSingleServiceFactory:createInstanceWithArguments  method. The returned  can then be queried for com.sun.star.script.XInvocation2 derived from com.sun.star.script.XInvocation.

The  interface invokes methods and access properties directly by passing their names and additional parameters to the corresponding methods (method ,   and  ). It is also possible to ask if a method or property exists with the methods  and.

When invoking a method with, the parameters are passed as a sequence of any values. The Invocation service automatically converts these arguments, if possible to the appropriate target types using the com.sun.star.script.Converter service that is further described below. The  functionality is suitable for binding scripting languages to UNO that are not or only weakly typed.

The  interface extends the   functionality by methods to ask for further information about the properties and methods of the object represented by the   instance. It is possible to ask for the names of all the properties and methods (method ) and detailed information about them represented by the com.sun.star.script.InvocationInfo struct type (methods   and  ).

The  service is based on the   service. The  interface has a method   to ask for the corresponding   interface. The  implementation currently implemented in LibreOffice supports this, but in general, an implementation of   does not provide access to an   interface.

InvocationAdapterFactory
The service com.sun.star.script.InvocationAdapterFactory supporting the interfaces com.sun.star.script.XInvocationAdapterFactory and com.sun.star.script.XInvocationAdapterFactory2 are used to create adapters that map a generic  interface to specific interfaces. This functionality is especially essential for creating scripting language bindings that do not only access UNO from the scripting language, but also to implement UNO objects using the scripting language. Without the  functionality, this would only be possible if the scripting language supported the implementation of interfaces directly.

By means of the  functionality it is only necessary to map the scripting language specific native invocation interface, for example, realized by an OLE   interface, to the UNO   interface. Then, any combination of interfaces needed to represent the services supported by a UNO object are provided as an adapter using the com.sun.star.script.XInvocationAdapterFactory2:createAdapter method.

Another important use of the invocation adapter is to create listener interfaces that are passed to the corresponding  method of an UNO interface and maps to the methods of an interface to. In this case, usually the com.sun.star.script.XInvocationAdapterFactory:createAdapter method is used.

XTypeDescription
Internally, types in UNO are represented by the type type. This type also has an interface representation com.sun.star.reflection.XTypeDescription. A number of interfaces derived from  represent types. These interfaces are:


 * com.sun.star.reflection.XArrayTypeDescription
 * com.sun.star.reflection.XCompoundTypeDescription
 * com.sun.star.reflection.XEnumTypeDescription
 * com.sun.star.reflection.XIndirectTypeDescription
 * com.sun.star.reflection.XUnionTypeDescription
 * com.sun.star.reflection.XInterfaceTypeDescription
 * com.sun.star.reflection.XInterfaceAttributeTypeDescription
 * com.sun.star.reflection.XInterfaceMemberTypeDescription
 * com.sun.star.reflection.XInterfaceMethodTypeDescription

The corresponding services are com.sun.star.reflection.TypeDescriptionManager and com.sun.star.reflection.TypeDescriptionProvider. These services support com.sun.star.container.XHierarchicalNameAccess and asks for a type description interface by passing the fully qualified type name to the com.sun.star.container.XHierarchicalNameAccess:getByHierarchicalName method.

The  services and interfaces are listed here for completeness. Ordinarily this functionality would not be used when binding a scripting language to UNO, because the high-level services,   and   provide all the functionality required. If the binding is implemented in C++, the  type and the corresponding C API are used directly.

The following illustration provides an overview of how the described services and interfaces work together. Each arrow expresses a "uses" relationship. The interfaces listed for a service are not necessarily supported by the service directly, but contain interfaces that are strongly related to the services.



Scripting Existing UNO Objects
This section describes UNO bridges for type-unsafe (scripting) programming languages. These bridges are based on the com.sun.star.script.Invocation service.

The most common starting point for a new scripting language binding is that you want to control LibreOffice from a script running externally. To accomplish this, you need to know what your scripting language offers to extend the language, for example, Python or Perl extend the language with a module concept using locally shared libraries.

In general, your bridge must offer a static method that is called from a script. Within this method, bootstrap a UNO C++ component context as described in Bootstrapping a Service Manager.

Proxying a UNO Object
Next, this component context must be passed to the script programmer, so that you can instantiate a com.sun.star.bridge.UnoUrlResolver and connect to a running office within the script.

The component context can not be passed directly as a C++ UNO reference, because the scripting engine does not recognize it, therefore build a language dependent proxy object around the C++ object Reference.



For example, Python offers an API to create a proxy. Typically calls invoked on the proxy from a script are narrowed into one single C function. The Python runtime passes method names and an array containing the arguments to this C function.

If a proxy is implemented for a concrete interface, the method names that you received could in theory be compared to all method names offered by the UNO interface. This is not feasible, because of all the interfaces used in LibreOffice. The com.sun.star.script.Invocation service exists for this purpose. It offers a simple interface com.sun.star.lang.XSingleServiceFactory that creates a proxy for an arbitrary UNO object using the  method and passing the object the proxy acts for. Use the com.sun.star.script.XInvocation interface that is exported by this proxy to invoke a method on the UNO object.



Argument Conversion
In addition, argument conversion must be considered by specifying how each UNO type should be mapped to your target language.

Convert the language dependent data types to UNO data types before calling com.sun.star.script.XInvocation:invoke and convert the UNO datatypes (return value and out parameters) to language dependent types after the call has been exectuted. The conversion routines are typically recursive functions, because data values are nested in complex types, such as  or.

When UNO object references are returned by method calls to UNO objects, create new language dependent proxies as discussed above. When passing a previously returned UNO object as a parameter to a new method call, the language binding must recognize that it is a proxied object and pass the original UNO object reference to the com.sun.star.script.XInvocation:invoke call instead.

A special case for conversions are UNOIDL structs. You want to call a method that takes a struct as an argument. The first problem is the struct must be created by the bridge and the script programmer must be able to set members at the struct. One solution is that the bridge implementer creates a UNO struct using core C functions from the  library, but this is complicated and results in a lot of difficulty.

Therefore, a solution has been created that accesses structs through the  interface, as if they were UNO objects. This simplifies struct handling for bridge programmers. Refer to the reference documentation of com.sun.star.reflection.CoreReflection and the com.sun.star.script.Invocation service and the com.sun.star.beans.XMaterialHolder interface.

Exception Handling
UNO method calls may throw exceptions and must be mapped to the desired target language appropriately, depending on the capabilities of your target language. Ideally, the target language supports an exception concept, but error handlers, such as in LibreOffice Basic can be used also. A third way and worst case scenario is to check after every API call if an exception has been thrown,. In case the UNO object throws an exception, the  proxy throws a com.sun.star.reflection.InvocationTargetException. The exception has an additional any member, that contains the exception that was really thrown.

Note that the  proxy may throw a com.sun.star.script.CannotConvertException indicating that the arguments passed by the script programmer cannot be matched to the arguments of the desired function. For example, there are missing arguments or the types are incompatible. This must be reported as an error to the script programmer.

Property Support
The com.sun.star.script.Invocation has special  and   methods. These methods are used when the UNO object supports a property set and your target language, for example, supports something similar to the following:

object.propname = 'foo';.

Note that every property is also reachable by com.sun.star.script.XInvocation:invoke, so these set or  functions are optional.

Implementing UNO objects
When it is possible to implement classes in your target language, consider offering support for implementation of UNO objects. This is useful for callbacks, for example, event listeners. Another typical use case is to provide a datasource through a com.sun.star.io.XInputStream.

The script programmer determines which UNOIDL types the developed class implements, such as flagged by a special member name, for example, such as.

When an instance of a class is passed as an argument to a call on an external UNO object, the bridge code creates a new language dependent proxy that additionally supports the  interface. The bridge code hands the  reference of the bridge's proxy to the called object. This works as long as the com.sun.star.script.XInvocation:invoke method is used directly, for instance LibreOffice Basic, except if the called object expects an.

The com.sun.star.script.InvocationAdapterFactory service helps by creating a proxy for a certain object that implements  and a set of interfaces, for example, given by the   variable. The proxy returned by the  method must be passed to the called object instead of the bridge's   implementation. When the Adapter is queried for one of the supported types, an appropriate proxy supporting that interface is created.

If a UNO object invokes a call on the object, the bridge proxy's com.sun.star.script.XInvocation:invoke method is called. It converts the passed arguments from UNO types to language dependent types and conversely using the same routines you have for the other calling direction. Finally, it delegates the call to the implementation within the script.



It may become difficult if you do not want to start with an external scripting engine, but want to use the scripting engine inside the LibreOffice process instead. This must be supported by the target language. Often it is possible to load some library dynamically and access the scripting runtime engine through a C API. It should be implemented as a UNO C++ component. There are currently no generic UNO interfaces for this case, except for the com.sun.star.loader.XImplementationLoader. Define your own interfaces that best match your requirements. You might instantiate from Basic and retrieve an initial object or start a script. Future versions of LibreOffice may have a more comprehensive solution.

Example: Python Bridge PyUNO
This section provides an example of how the Python UNO bridge PyUNO bootstraps a service manager and how it makes use of the Invocation service to realize method invocation. While some parts are implementation or Python specific, the example provides a general understanding of language bindings.

The Python bridge PyUNO uses the cppu helper library to bootstrap a local service manager that is asked for a  service in Python.

In UNO.py, Python calls  and receives a local component context. Note the parameter setup in that, it points to an ini file that configures the bootstrapped service manager with a type library. The file setup.ini corresponds to the uno.ini file that is used with the global service manager of the office.

Python uses function tables to map Python to C functions. PyUNO_module.cc defines a table with the mappings for the PyUNO object. As shown in the following example,  is mapped to the C function  :

The function  calls   in PyUNO_Util.cc and passes the location of the setup.ini file.

uses  from cppuhelper/bootstrap.hxx to create a local component context and its parameter   points to the setup.ini file that configures the local service manager to use service.rdb and types.rdb (until OpenOffice.org 1.1.0 applicat.rdb). This local component context instantiates services, such as the.

Now  continues to set up a UNO proxy. It creates local instances of com.sun.star.script.Invocation and com.sun.star.script.Converter, and calls , passing the local  , a reference to the   interface of com.sun.star.script.Invocation and a reference to the   interface of com.sun.star.script.Converter.

in PyUNO.cc is the function responsible for building all Python proxies. The call to  here in   builds the first local PyUNO proxy for the   object a which has been returned by.

For this purpose,  uses the Invocation service to retrieve an XInvocation2 interface to the   service passed in the parameter a:

The Python proxy invokes methods, and creates and converts UNO types. This Python specific and involves the implementation of several functions according to the Python API.

Finally  in UNO.py in the above example uses the PyUNO object to obtain a local   that retrieves the initial object from the office.

Implementation Loader
When you are raising a service by name using the com.sun.star.lang.ServiceManager service, the service manager decides an implementation name, code location and an appropriate loader to raise the code. It is commonly reading out of a persistent registry storage, for example, services.rdb (until OpenOffice.org 1.1.0 applicat.rdb), for this purpose. Previously, the regcomp tool has registered components into that registry during the LibreOffice setup. The tool uses a service called com.sun.star.registry.ImplementationRegistration for this task.

A loader knows how to load a component from a shared library, a .jar or script file and is able to obtain the service object factory for an implementation and retrieve information being written to the registry. A specific loader defines how a component implementer has to package code so that it is recognized by UNO. For instance in C++, a component is a shared library and in Java it is a .jar file. In a yet to be developed loader, the implementer of the loader has to decide, what a component is in that particular language - it might as well be a single script file.

The com.sun.star.loader.XImplementationLoader interface looks like the following:

The  argument describes the location of the implementation file, for example, a jar file or a shared library. The  argument is not used and is obsolete. The registry key xKey writes information about the implementations within a component into a persistent storage. Refer to Write Registration Info Using a Helper Method for additional information.

The method  is called by the regcomp tool to register a component into a registry.

The  method returns a factory com.sun.star.lang.XSingleComponentFactory for a concrete implementation name.



The loader is often implemented in C/C++. When the loader is instantiated, it is responsible for starting up the language runtime, for example, Java VM, Python interpreter, through implementation. After starting up the runtime, the loader starts up the UNO language binding as discussed in the previous chapter, and bridge the  interface and the initial factory interface.

Shared Library Loader
This section discusses the loader for local components written in C++ that are loaded by the com.sun.star.loader.SharedLibrary service. Every type safe programming language that stores its code in shared libraries should implement the bridge with environments and mappings as discussed in chapters UNO Bridge and UNO C++ Bridges. These programming languages can reuse the existing loader without creating a new one.

When the shared library is mapped into the running process, for example, using, the shared library loader retrieves defined C symbols out of the library to determine the compiler that built the code. This function symbol is called. When the code is compiled with the Microsoft Visual C++ compiler, it sets a pointer to a string called " ", with gcc 3.0.1 a string " " which is a UNO environment type name. A UNO environment is connected with the code that runs in it, for example, the code compiled with gcc3 runs in the UNO environment with type name gcc3.

In addition to the environment type name, a UNO environment defines a context pointer. The context pointer and environment type name define a unique UNO environment. Although the context pointer is mostly null, it is required to identify the environments apart for the same type, for example, to identify different Java virtual machine environments when running a UNO object in two different Java virtual machines within the same process. Both environments have the same type name "java", but different context pointers. In local (C++) code, the context pointer is irrelevant, that is, set to null. The type name determines the UNO runtime environment.

When the loader knows the environment the code comes from, it decides if bridging is required. Bridging is needed if the loader code is compiled with a different compiler, thus running in a different environment. In this case, the loader raises a bridge to speak UNO with the component code.

The loader calls on two more functions related to the above  interface. All of these symbols are C functions and have the following signatures:

The latter two functions expect incoming C++-UNO interfaces, therefore the loader needs to bridge interfaces before calling the functions as stated above.

Bridges
The loader uses the cppu core runtime to map an interface, specifying the UNO runtime environment that needs the interface mapping. The cppu core runtime raises and connects the appropriate bridges, and provides a unidirectional mapping that uses underlying bidirectional bridges. Under Unix, the name of the bridge library follows the naming convention ''lib and   functions for reference counting. The minimum life time of an object is managed by means of reference counting.


 * Mandatory Base Exception
 * UNO specifies a mandatory base exception for all exceptions. This base exception contains a string member  that describes the reason for the exception in readable format. The base exception makes it also possible to catch all UNO exceptions separately.


 * Method Context
 * CORBA supports a request context. This context consists of a name-value pair which is specified for methods in UNOIDL. The context is used for describing the current state of the caller object. A request context provides additional, operation-specific information that may affect the performance of a request.


 * Type
 * UNO does not support 8-bit characters. In UNO, char represents a 16-bit unicode character.Mapping: To support 8-bit characters it is possible to expand the  enum to support 8-bit characters and strings. The internal representation does not change anything, the   is only relevant for mapping.


 * 8 bit string
 * UNO does not support 8-bit strings. In UNO,  represents a 16-bit unicode string.
 * Mapping: The same possibility as for char.


 * Type
 * UNO does not support arrays at the moment, but is planned for the future.


 * Type
 * UNO does not support unions at the moment, but is planned for the future.


 * Assigned Values for
 * UNO supports the assignment of values for enum values in IDL. This means that it is possible to use these values directly to specify or operate with the required enum value in target languages supporting this feature, for example, . C, C++.
 * Mapping: Possible by using the names of the values.

UNO Design Patterns and Coding Styles
This chapter discusses design patterns and coding recommendations for LibreOffice. Possible candidates are:


 * Singleton: global service manager, Desktop, UCB
 * Factory: decouple specification and implementation, cross-environment instantiation, context-specific instances
 * Listener: eliminate polling
 * Element access: it is arguable if that is a design pattern or just an API
 * Properties: solves remote batch access, but incurs the problem of compile-time type indifference
 * UCB commands: universal dispatching of content specific operations
 * Dispatch commands: universal dispatching of object specific operations, chain of responsibility

Double-Checked Locking
The double-checked locking idiom is sometimes used in C/C++ code to speed up creation of a single-instance resource. In a multi-threaded environment, typical C++ code that creates a single-instance resource might look like the following example:

A mutex guards against multiple threads simultaneously updating, and the nested static   is guaranteed to be created only when first needed, and destroyed when the program terminates.

The disadvantage of the above function is that it must acquire and release the mutex every time it is called. The double-checked locking idiom was developed to reduce the need for locking, leading to the following modified function. Do not use.:

This version needs to acquire and release the mutex only when  has not yet been initialized, resulting in a possible performance improvement. The mutex is still needed to avoid race conditions when multiple threads simultaneously see that  is not yet initialized, and all want to update it at the same time. The problem with  is that it does not work.

Assume that thread 1 calls  first, finding   uninitialized. It acquires the mutex, creates  that results in writing data into  's memory, updates   that results in writing data into  's memory, and releases the mutex. Some hardware memory models a write the operations that transfer 's and  's data to main memory to be re-ordered by the processor executing thread 1. Now, if thread 2 enters  when  's data has already been written to main memory by thread 1, but aInstance's data has not been written yet (remember that write operations may be done out of order), then thread 2 sees that   has already been initialized and exits from   directly. Thread 2 dereferences  thereafter, accessing  's memory that has not yet been written into. Anything may happen in this situation.

In Java, double-checked locking can never be used, because it is broken and cannot be fixed.

In C and C++, the problem can be solved, but only by using platform-specific instructions, typically some sort of memory-barrier instructions. There is a macro  in osl/doublecheckedlocking.h that uses the double-checked locking idiom in a way that actually works in C and C++.

The first (inner) use of  ensures that  's data has been written to main memory before  's data is written, therefore a thread can not see   to be initialized when  's data has not yet reached main memory. This solves the problem described above.

The second (outer) usage of  is required to solve a problem concerning the reordering on Alpha processors.

If you are coding in C++, there is an easier way to use double-checked locking without worrying about the fine points. Use the rtl_Instance template from rtl/instance.hxx:

Note that an extra function class is required in this case. The documentation of rtl_Instance contains further examples of how this template can be used.