UNO registery and Bootstrapping

From Apache OpenOffice Wiki
Jump to: navigation, search

OpenOffice.org can be extended; you can add features using a number of different programming languages, including OOoBasic, C++, Java, and Python. These added features are called Add-Ons, components, Add-ins (discussed here) and we can wonder how Openoffice.org knows something about the corresponding code ? The tools involved in this chapter are regview, regcomp, regmerge and idlc.

Why UNO registry ?

It is common for programmer to develop a program and link it with a static library. If the library is a dynamic one the linking problem is let to Operating System : this OS have to know if the library is already loaded and if not where it lies. Let us be more concrete with an example.

LibraryExample.png

In the example above in Figure above our program example.cxx calls something in mylib.so or mylib.dll (the arrow means an interaction). This is done in a very simple way if both are compiled with same language : under Linux we use a -Lmylib.so when compiling example.cxx (more here). Then when you launch example binary executable when it needs what is in mylib.so it asks OS to load it. The case is a little more complicated if mylib.so is compiled with an other language than C++ : you have to learn how to pass parameters in C++ to reach the content of mylib.so. This is feasible changing a little example.cxx code. But what happens if you have a binary executable program and you want to give him new features with a dynamic library ? This can be done with OpenOffice.org as already mentioned.

What kind of problems OpenOffice has then to carry out ?

First of all, it is impossible for Openoffice.org to know in advance what is the name of the library (it's a name you choose). Then OpenOffice.org must provide a mechanism to know its name : this is one of the goals of registry. Is the name of the dynamic library enough ? No, if you imagine you can extend with two or more libraries : it is important to know that foo1 procedure/method comes from foo_lib1 library and foo2 from foo_lib2... In OpenOffice.org this is generalized saying such an interface comes from such a library ... There is a lot of other problems to resolve before making it working properly. For example a problem with the name of procedure/methods : if you write it in C or in C++ the exported names will differ.

And the parameters, how do you pass them ? Imagine OOoCalc call something in mylib.so : it is unimaginable to ask OOocalc users to write something describing how parameters are passed in their OOoCalc formula ! OpenOffice has to know how pass a parameter in your library. This is done with what is called implementation environment. This done with specifying that every dynamic library has to export :

//Listing 1  How to get the Implementation Environnement in a dynamic library
// C++
extern "C" 
void SAL_CALL component_getImplementationEnvironment( 
                 const sal_Char ** ppEnvTypeName, 
                 uno_Environment ** ppEnv )

The passing parameters way is fixed by extern C. This is not a decoration but an obligation. If not present a ["component_getImplementationEnvironment" could not be found] error will be thrown when you try to registry (with regmerge for instance).

Registery uses rdb files in a binary file format. Binaries format are difficult to read by human and then a tool is provided to give the information in human readable form (see regview in further section).

Template:Documentation/Tip

Template:Documentation/Note

How to use UNO registeries

Documentation for registries already exist at : uno registeries. More information at : ooomacros where these tools are available :

  • Add On Tool

Author: Bernard Marcelly

  • Add On Installer

Author: Didier Lachièze, with code from Danny Brewer, Bernard Marcelly and Andrew Brown

  • Basic Library Installer

Author: Danny Brewer, with code from Andrew Brown & Didier Lachièze

In my opinion, the simpler way to registery is to modify the file unorc (under linux) or uno.ini (under Windows). You have to put the file your_library.uno.rdb in <OOo>/program directory, and editing/modifying the file <OOo>/program/unorc (under linux) adding (last line your_library.uno.rdb) :

#unorc or uno.ini
[Bootstrap] 
UNO_SHARED_PACKAGES=${$SYSBINDIR/bootstraprc:BaseInstallation}/share/uno_packages 
UNO_SHARED_PACKAGES_CACHE=$UNO_SHARED_PACKAGES/cache 
UNO_USER_PACKAGES=${$SYSBINDIR/bootstraprc:UserInstallation}/user/uno_packages 
UNO_USER_PACKAGES_CACHE=$UNO_USER_PACKAGES/cache 
UNO_TYPES=$SYSBINDIR/types.rdb ?$UNO_SHARED_PACKAGES_CACHE/types.rdb ?$UNO_USER_PACKAGES_CACHE/types.rdb 
UNO_SERVICES= ?$UNO_USER_PACKAGES_CACHE/services.rdb ?$UNO_SHARED_PACKAGES_CACHE/services.rdb $SYSBINDIR/services.rdb ?$SYSBINDIR/your_library.uno.rdb

Don't forget to register the location of your_library.uno.so in the your_library.uno.rdb. This is done with regcomp tool :

regcomp -Register -r your_library.uno.rdb -c <somewhere>/your_library.uno.so

An other way is to use pkgchk or the recent unopkg for Ooo2.0x.

The Bootstrap

Bootstrapping can be defined in saying it's the way to obtain a service manager. We present two different examples of bootstraping.

C++ UNO bootstrapping via defaultBootstrap_InitialComponentContext()

We have have already described this bootstrap method because it concerns the classical SDK example we started with in chapter 4 (see <OpenOffice.org1.1_SDK>/examples/DevelopersGuide/ProfUNO/CppBinding). We provide here two different views to explain how it works.

Interfaces ans Services with defaultBootstrap_InitialComponentContext()

First we recall with the Figure below how we program it. It's easy to see the first C++ instruction is

//C++
defaultBootstrap_InitialComponentContext();

But when drawing details from the figure we cannot infer how it works and particularly with registery. It's only because Figure below is a C++/Java programmer point of view.

Ch4Fig1bootstrap.png

defaultBootstrap_InitialComponentContext() is a buit-in function which return a com.sun.star.uno.XComponentContext interface, as alrady explained. This interface has a method "getServiceManager" which allow us obtaining service manager (as a com.sun.star.lang.XMultiComponentFactory type variable). It's an interface whch contain method "createInstanceWithContext" among others, wich uses two parameters, the string "com.sun.star.bridge.UnoUrlResolver" and the previous variable of type com.sun.star.uno.XComponentContext. We can follow the schematic until the bottom, but we let it as an excercise (See also com.sun.star.uno.XInterface, com.sun.star.bridge.XUnoUrlResolver and com.sun.star.lang.XMultiServiceFactory interfaces).

How defaultBootstrap_InitialComponentContext() bootstrapping works

To see what happens during the beginning of bootstrap, we go and see the binary in <OpenOffice.org1.1_SDK>/LINUXexample.out/bin where binaries are constructed by default makefiles. We see three files :

  • office_connect the binary executable
  • office_connectrc : file with this content :
UNO_TYPES=$SYSBINDIR/office_connect.rdb
UNO_SERVICES=$SYSBINDIR/office_connect.rdb
  • office_connect.rdb

The files construction will perhaps help us to understand beter. We give again the compilation chain of office_connect in Figure 1.4 which shows us how office_connect.rdb is constructed :

  • a regmerge starting from types.rdb
  • a regcomp to register somes classics uno.so files.

And now to learn how office_connect.rdb is used we have to search in makefile how the binary is launched : the line

office_connect.run : $(OUT_COMP_BIN)/$(OUTBIN) $(OUT_COMP_BIN)/office_connectrc
	cd $(OUT_COMP_BIN) && $(OUTBIN)

is expanded as

cd ../../../../LINUXexample.out/bin && office_connect

but shows also a dependance to office_connectrc. We want to go further and see how things work.

  • the office_connectrc is automaticly loaded. One way to check that is to rename this file (as office_connectrc2 for instance) which gives as result
make: *** [office_connect.run] Erreur 134
  • renaming only office_connect.rdb (as office_connect2.rdb for instance) gives the same error :
make: *** [office_connect.run] Erreur 134
  • renaming office_connect.rdb as office_connect2.rdb and changing office_connectrc content, as seen below, works well.
UNO_TYPES=$SYSBINDIR/office_connect2.rdb
UNO_SERVICES=$SYSBINDIR/office_connect2.rdb

Conclusion : we have found how it works : when you launch a binary it automaticaly load office_connectrc which provide the information where office_connect.rdb file is.

C++ UNO bootstrapping via Bootstrap_InitialComponentContext()

The documentLoader example (see <OpenOffice.org1.1_SDK>/examples/cpp/DocumentLoader) uses an other way to bootstrap. We want to describe it now. As usualy we first begin with program framework in the Figure below.

SecondBootstrap.png

In this second case we clearly see that DocumentLoader.rdb file is involved and loaded (created in makefile with regmerge utility). The only difference is, we find again a rdb file but not a rc file. The consequence is the presence of a regcomp command specific to regitery the binary/executable file.

This example will not work if OpenOffice.org is not running. In this example, the interaction between OpenOffice.org and some.bin is through the network. In other words, the programs can run on different computers. You must run OpenOffice.org in such a way it waits for an UNO connection (here only from localhost) :

<Ooo>/program/soffice "-accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager"

The new ::cppu::bootstrap() function

As explained in Developer's Guide a new function is available now for bootstrapping. See the corresponding code in Developer's Guide. I have found also in oooForum the snippet below which illustrate how it works.

Reference <XComponentContext> x_component_context(::cppu::bootstrap());
      _x_multi_component_factory_client = Reference <XMultiComponentFactory> (x_component_context->getServiceManager());
      _x_interface = Reference <XInterface>(_x_multi_component_factory_client->createInstanceWithContext(OUString::createFromAscii("com.sun.star.bridge.UnoUrlResolver" ), x_component_context));
      Reference <XUnoUrlResolver> resolver(_x_interface, UNO_QUERY);
      _x_interface = Reference <XInterface> (resolver->resolve(connection_string), UNO_QUERY);
        Reference <XPropertySet> x_prop_set(_x_interface, UNO_QUERY);
        x_prop_set->getPropertyValue(OUString::createFromAscii("DefaultContext")) >>= x_component_context;
        Reference <XMultiComponentFactory> x_multi_component_factory_server(x_component_context->getServiceManager());
        _x_component_loader = Reference <XComponentLoader>(x_multi_component_factory_server->createInstanceWithContext(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")), x_component_context), UNO_QUERY);

If you want to use this new function, have a look in, <OOo_SDK>examples/DevelopersGuide/ProfUno/SimpleBootstrap_cpp, and as usual modify the file SimpleBootstrap_cpp.cxx without modifying makefile. Template:Documentation/Note

Playing with regview

This page is a short article on something that should have a lot more information written on it. If you know anything else about it, you are STRONGLY encouraged to add the information in. If you are unsure of proper formatting or style, add it to the talk page or this page itself as you think best and others will help.


How can we registry in C++ ?

It is easy to find an example with registry. As first example we can take the counter example. Why it's an interesting example is only because it's a two files example : counter.cxx and countermain.cxx. Counter.cxx is compiled in counter.uno.so (counter.uno.dll in windows plateforms) and a counter.uno.rdb file is created. As shown above this file is for registry.

But what is new is, registry will be performed by the second program : countermain.cxx. And then reading this file gives us the possibility to view how this is done in C++ (see the below)

//Listing 2 Countermain.cxx example
// C++
	....

	// register my counter component
	Reference< XImplementationRegistration > xImplReg(
		xMgr->createInstanceWithContext(OUString::createFromAscii(
                     "com.sun.star.registry.ImplementationRegistration"), xContext), UNO_QUERY);
	OSL_ENSURE( xImplReg.is(), 
           "### cannot get service instance of \"com.sun.star.registry.ImplementationRegistration\"!" );

	if (xImplReg.is())
	{
		xImplReg->registerImplementation(
			OUString::createFromAscii("com.sun.star.loader.SharedLibrary"), 
			// loader for component
#ifdef UNX
#ifdef MACOSX
			OUString::createFromAscii("counter.uno.dylib"),		// component location
#else
			OUString::createFromAscii("counter.uno.so"),		// component location
#endif
#else
			OUString::createFromAscii("counter.uno.dll"),		// component location
#endif
			Reference< XSimpleRegistry >()	 // registry omitted,
											 // defaulting to service manager registry used
			);

An other look into countermain.cxx file is showing the bootstrap is achieved like in the DocumentLoader example and then provide the XComponentContext (xContext) and XMultiComponentFactory (xMgr) useful for registry. We cannot continue without wondering what is XImplementationRegistration interface ? We gives again the corresponding IDL file :

// IDL
module com {  module sun {  module star {  module registry {
interface XImplementationRegistration: com::sun::star::uno::XInterface
{
	void registerImplementation( [in] string aImplementationLoader, 
			 [in] string aLocation, 
			 [in] com::sun::star::registry::XSimpleRegistry xReg ) 
			raises( com::sun::star::registry::CannotRegisterImplementationException ); 
	boolean revokeImplementation( [in] string aLocation, 
			 [in] com::sun::star::registry::XSimpleRegistry xReg ); 
	sequence<string> getImplementations( [in] string aImplementationLoader, 
			 [in] string aLocation ); 
	sequence<string> checkInstantiation( [in] string implementationName );

};
}; }; }; };

We see new methods and among others one we want to test: getImplementations. We then add this code in the countermain.cxx

//Listing 3 The countermain.cxx example modified
// C++
		Sequence <OUString> OUStrs =xImplReg->getImplementations(
				OUString::createFromAscii("com.sun.star.loader.SharedLibrary"),
				OUString::createFromAscii("counter.uno.so"));
		for (int i=0;i<OUStrs.getLength();i++){
			OString toPrintOut = OUStringToOString(OUStrs[i],RTL_TEXTENCODING_ASCII_US);
			printf("-- %s\n",toPrintOut.pData->buffer);
		}

which prints out :

< MyCounterImpl ctor called >
42,43,42
-- com.sun.star.comp.example.cpp.Counter
< MyCounterImpl dtor called >

This means : if I use SharedLibrary service to load counter.uno.so, I will have the implementation name « com.sun.star.comp.example.cpp.Counter ». This information is stored in registery as Developpers Guide states. In our example :

[smoutou@p3 counter]$ regview ../../../LINUXexample.out/bin/counter.uno.rdb /IMPLEMENTATIONS 

gives the result :

Listing 5 Content of the key /IMPLEMENTATION
Registry "file:///home/smoutou/OpenOffice.org1.1_SDK/LINUXexample.out/bin/counter.uno.rdb":

/IMPLEMENTATIONS
 / com.sun.star.comp.example.cpp.Counter
   / UNO
     / ACTIVATOR
       Value: Type = RG_VALUETYPE_STRING
              Size = 34
              Data = "com.sun.star.loader.SharedLibrary"
 
     / SERVICES
       / foo.Counter
     / LOCATION
       Value: Type = RG_VALUETYPE_STRING
              Size = 15
              Data = "counter.uno.so"

where we see the association between « com.sun.star.comp.example.cpp.Counter » name and a dynamic library (under Linux) « counter.uno.so »

It is possible to get the service name :

Listing 6  Retrieving the Service Name
[smoutou@p3 counter]$ regview ../../../LINUXexample.out/bin/counter.uno.rdb /IMPLEMENTATIONS/com.sun.star.comp.example.cpp.Counter/UNO/SERVICES
Registry "file:///home/smoutou/OpenOffice.org1.1_SDK/LINUXexample.out/bin/counter.uno.rdb":
 
/IMPLEMENTATIONS/com.sun.star.comp.example.cpp.Counter/UNO/SERVICES
 / foo.Counter
[smoutou@p3 counter]$

Here the result is « foo.Counter ». We want to retrieve the information of Listing 6 but with C++ programming. Again you can modify the countermain.cxx example (just after the last line given in Listing 2) as shown below :

//Listing 7 Retrieving the Service Name in C++
// C++
		Sequence <OUString> OUStrs =xImplReg->getImplementations(
				OUString::createFromAscii("com.sun.star.loader.SharedLibrary"),
				OUString::createFromAscii("counter.uno.so"));
		for (int i=0;i<OUStrs.getLength();i++){
			OString toPrintOut = OUStringToOString(OUStrs[i],RTL_TEXTENCODING_ASCII_US);
			printf("-- %s\n",toPrintOut.pData->buffer);
		}
		OUStrs = xImplReg->checkInstantiation(
			OUString::createFromAscii("foo.Counter"));
		printf("****\n");
		for (int i=0;i<OUStrs.getLength();i++){
			OString toPrintOut = OUStringToOString(OUStrs[i],RTL_TEXTENCODING_ASCII_US);
			printf("** %s\n",toPrintOut.pData->buffer);
		}

		Reference< XSimpleRegistry > xSimpleReg(
		xMgr->createInstanceWithContext(OUString::createFromAscii("com.sun.star.registry.SimpleRegistry"), xContext), UNO_QUERY);
		if(xSimpleReg.is())printf("OK XSimpleRegistry\n");

		xSimpleReg->open(OUString::createFromAscii(
       "file:///home/smoutou/OpenOffice.org1.1_SDK/LINUXexample.out/bin/counter.uno.rdb"),
        false,false);
// How to retrieve all the keys :
		Reference< XRegistryKey > xRegKey= xSimpleReg->getRootKey();
		if(xRegKey.is())printf("OK XRegistryKey\n");
		OUStrs = xRegKey->getKeyNames();
		printf("++++ \n");
		for (int i=0;i<OUStrs.getLength();i++){
			OString toPrintOut = OUStringToOString(OUStrs[i],RTL_TEXTENCODING_ASCII_US);
			printf("+++ %s\n",toPrintOut.pData->buffer);
// prints out : /UCR /IMPLEMENTATIONS /SERVICES
		}
// How to get a sub-key
		xRegKey=xRegKey->openKey(
		OUString::createFromAscii("/IMPLEMENTATIONS/com.sun.star.comp.example.cpp.Counter/UNO/SERVICES"));
		OUStrs = xRegKey->getKeyNames();
		printf("$$$$ \n");
		for (int i=0;i<OUStrs.getLength();i++){
			OString toPrintOut = OUStringToOString(OUStrs[i],RTL_TEXTENCODING_ASCII_US);
			printf("$$$ %s\n",toPrintOut.pData->buffer);
// prints out : 
// /IMPLEMENTATIONS/com.sun.star.comp.example.cpp.Counter/UNO/SERVICES/foo/Counter

		}

		xRegKey->closeKey();
		xSimpleReg->close();

which prints out

-- com.sun.star.comp.example.cpp.Counter
****
OK XSimpleRegistry
OK XRegistryKey
++++
+++ /UCR
+++ /IMPLEMENTATIONS
+++ /SERVICES
$$$$
$$$ /IMPLEMENTATIONS/com.sun.star.comp.example.cpp.Counter/UNO/SERVICES/foo.Counter

Registry tools in C++

Introduction

I want to retrieve and decode Binary information My choice is Xinterface for a test. I wonder if it's possible to retrieve all the information given by regview tool :

[smoutou@p3 counter]$ regview ../../../LINUXexample.out/bin/counter.uno.rdb /UCR/com/sun/star/uno/XInterface
Registry "file:///home/smoutou/OpenOffice.org1.1_SDK/LINUXexample.out/bin/counter.uno.rdb":
 
/UCR/com/sun/star/uno/XInterface
 Value: Type = RG_VALUETYPE_BINARY
        Size = 326
        Data = minor version: 0
               major version: 1
               type: 'interface'
               uik: { 0x00000000-0x0000-0x0000-0x00000000-0x00000000 }
               name: 'com/sun/star/uno/XInterface'
               super name: ''
               Doku: ""
               IDL source file: "/home/gb/rpm/BUILD/oo_1.1rc4_src/udkapi/com/sun/star/uno/XInterface.idl"
               number of fields: 0
               number of methods: 3
               method #0: any queryInterface([in] type aType)
                 Doku: ""
               method #1: [oneway] void acquire()
                 Doku: ""
               method #2: [oneway] void release()
                 Doku: ""
               number of references: 0
 
[smoutou@p3 counter]$

C++ Code to recover Information in a Binary Sequence

See the listing below to learn how we can recover binary information in registery.

//Listing 8 Retrieving Information in a Binary Sequence
// C++
....
		Reference< XSimpleRegistry > xSimpleReg(
		xMgr->createInstanceWithContext(OUString::createFromAscii(
                          "com.sun.star.registry.SimpleRegistry"), xContext), UNO_QUERY);
		OSL_ENSURE(xSimpleReg.is(),"NOK XSimpleRegistry\n");

		xSimpleReg->open(OUString::createFromAscii(
       "file:///home/smoutou/OpenOffice.org1.1_SDK/LINUXexample.out/bin/counter.uno.rdb"),
        false,false);
// How to retrieve all the keys :
		Reference< XRegistryKey > xRegKey= xSimpleReg->getRootKey();
		OSL_ENSURE(xRegKey.is(),"NOK XRegistryKey\n");
// How to get a sub-key
		xRegKey=xRegKey->openKey(
    		OUString::createFromAscii("/UCR/com/sun/star/uno/XInterface"));

		printf("//// \n");
		OUString OUStr;
		OString toPrintOut; 
		Sequence< sal_Int8 > seqByte;
// still a lot to do in this switch :
		switch (xRegKey->getValueType()){
		  case RegistryValueType_LONG : printf("long\n");break;
		  case RegistryValueType_ASCII : printf("ascii\n");
			OUStr = xRegKey->getAsciiValue();
			toPrintOut = OUStringToOString(OUStr,RTL_TEXTENCODING_ASCII_US);
			printf("/// %s\n",toPrintOut.pData->buffer);
			break;
		  case RegistryValueType_STRING : printf("string\n");break;
		  case RegistryValueType_BINARY : printf("RG_VALUETYPE_BINARY\n");
			seqByte = xRegKey->getBinaryValue();
			printDEBUGMODE(seqByte);
			break;
		  case RegistryValueType_LONGLIST : printf("long list\n");break;
		  case RegistryValueType_ASCIILIST : printf("ascii list\n");break;
		  case RegistryValueType_STRINGLIST : printf("string list\n");break;
		  case RegistryValueType_NOT_DEFINED : printf("not defined\n");break;
		}
....
// with the procedure
void printDEBUGMODE(Sequence < sal_Int8 > seqBytes){
  sal_Int8 Hexa[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  int lin,col;
  sal_Int8 line[80];
  sal_Int32 len;
  len=seqBytes.getLength();
  // print the lenght in decimal and with 4 hexadecimal digits (C notation 0x....)
  printf("length : %d Ox%X%X%X%X\n",len,len>>12&0x000F,len>>8&0x000F,len>>4&0x000F,len&0x000F);
  len = (len/16)*16; // retire le modulo 16
  for(lin=0;lin<len;lin=lin+16){
      for(col=0;col<16;col++){
        line[3*col]=Hexa[seqBytes[lin+col]>>4];
	line[3*col+1]=Hexa[seqBytes[lin+col]&0x0F];
	line[3*col+2]=' ';
        if ((seqBytes[lin+col]<128)&&(seqBytes[lin+col]>20)) line[50+col]=seqBytes[lin+col];
        else line[50+col]='.';
      } /* end of for */
      line[66]=0; /* end of string...*/
      line[48]=' ';line[49]=' ';
      for (int i=0;i<66;i++)
        printf("%c",static_cast< char >(line[i]));
      printf("\n");
  } /* end of for */ 
  // the last line is more complicated because not complete
  for (lin=len;lin<seqBytes.getLength();lin++){
    col=lin-len;
    line[3*col]=Hexa[seqBytes[lin]>>4];
    line[3*col+1]=Hexa[seqBytes[lin]&0x0F];
    line[3*col+2]=' ';
    if ((seqBytes[lin]<128)&&(seqBytes[lin]>20)) line[50+col]=seqBytes[lin];
    else line[50+col]='.';
  }
  for (++col;col<16;col++){
	line[3*col]=' ';line[3*col+1]=' ';line[3*col+2]=' ';line[50+col]=' ';
  }
  line[66]=0; /* end of string...*/
  line[48]=' ';line[49]=' ';
  for (int i=0;i<66;i++)
    printf("%c",static_cast< char >(line[i]));
  printf("\n"); 
}

A carrefully look at the listing above shows we transform the sequence of bytes in a format which recalls the old DOS debug tool.

////
RG_VALUETYPE_BINARY
length : 326 Ox0146
12 34 56 78 00 00 01 46 00 00 00 01 00 06 00 00   .4Vx...F........
00 01 00 01 00 02 00 00 00 03 00 00 00 0B 00 00   ................
00 22 00 0C 63 6F 6D 2F 73 75 6E 2F 73 74 61 72   ."..com/sun/star
2F 75 6E 6F 2F 58 49 6E 74 65 72 66 61 63 65 00   /uno/XInterface.
00 00 00 16 00 0D 00 00 00 00 00 00 00 00 00 00   ...............
00 00 00 00 00 00 00 00 00 4E 00 0C 2F 68 6F 6D   .........N../hom
65 2F 67 62 2F 72 70 6D 2F 42 55 49 4C 44 2F 6F   e/gb/rpm/BUILD/o
6F 5F 31 2E 31 72 63 34 5F 73 72 63 2F 75 64 6B   o_1.1rc4_src/udk
61 70 69 2F 63 6F 6D 2F 73 75 6E 2F 73 74 61 72   api/com/sun/star
2F 75 6E 6F 2F 58 49 6E 74 65 72 66 61 63 65 2E   /uno/XInterface.
69 64 6C 00 00 00 00 15 00 0C 71 75 65 72 79 49   idl......queryI
6E 74 65 72 66 61 63 65 00 00 00 00 0A 00 0C 61   nterface.......a
6E 79 00 00 00 00 0B 00 0C 74 79 70 65 00 00 00   ny.......type...
00 0C 00 0C 61 54 79 70 65 00 00 00 00 0E 00 0C   ....aType.......
61 63 71 75 69 72 65 00 00 00 00 0B 00 0C 76 6F   acquire.......vo
69 64 00 00 00 00 0E 00 0C 72 65 6C 65 61 73 65   id.......release
00 00 00 00 0B 00 0C 76 6F 69 64 00 00 00 00 03   .......void.....
00 05 00 03 00 14 00 03 00 04 00 05 00 00 00 01   ................
00 06 00 01 00 07 00 00 00 0E 00 01 00 08 00 09   ................
00 00 00 00 00 00 00 0E 00 01 00 0A 00 0B 00 00   ................
00 00 00 00 00 00                                 ......

[smoutou@p3 counter]$ 

We see it's possible to understand how these bytes are constituted to hold the information we look for, but it will take a while to investigate further. I prefere have a look into source code and find : « OOB680_m5/registry/source/reflcnst.hxx »

Examining the OOo source code

For instance before every name we see a « 00 0C » It's effecftively defined in reflcnst.hxx file as :

//Listing 9 reflcnst.hxx File (extract)
// C++
...
enum CPInfoTag 
{
	CP_TAG_INVALID = RT_TYPE_NONE,
	CP_TAG_CONST_BOOL = RT_TYPE_BOOL,
	CP_TAG_CONST_BYTE  = RT_TYPE_BYTE,
	CP_TAG_CONST_INT16 = RT_TYPE_INT16,
	CP_TAG_CONST_UINT16 = RT_TYPE_UINT16,
	CP_TAG_CONST_INT32 = RT_TYPE_INT32,
	CP_TAG_CONST_UINT32 = RT_TYPE_UINT32,
	CP_TAG_CONST_INT64 = RT_TYPE_INT64,
	CP_TAG_CONST_UINT64 = RT_TYPE_UINT64,
	CP_TAG_CONST_FLOAT = RT_TYPE_FLOAT,
	CP_TAG_CONST_DOUBLE = RT_TYPE_DOUBLE,
	CP_TAG_CONST_STRING = RT_TYPE_STRING,
	CP_TAG_UTF8_NAME,
	CP_TAG_UIK
};
....

which learns us this is an info tag of type CP_TAG_UTF8_NAME. If we want to decode header we use this extract :

//Listing 10 reflcnst.hxx File (extract)
// C++
extern const sal_uInt32	magic;
extern const sal_uInt16 minorVersion;
extern const sal_uInt16 majorVersion;

#define OFFSET_MAGIC 				0
#define OFFSET_SIZE 				(OFFSET_MAGIC + sizeof(magic))
#define OFFSET_MINOR_VERSION 		(OFFSET_SIZE + sizeof(sal_uInt32))
#define OFFSET_MAJOR_VERSION 		(OFFSET_MINOR_VERSION + sizeof(minorVersion))
#define OFFSET_N_ENTRIES   	 		(OFFSET_MAJOR_VERSION + sizeof(sal_uInt16))
#define OFFSET_TYPE_SOURCE    		(OFFSET_N_ENTRIES + sizeof(sal_uInt16))
#define OFFSET_TYPE_CLASS 			(OFFSET_TYPE_SOURCE + sizeof(sal_uInt16))
#define OFFSET_THIS_TYPE 			(OFFSET_TYPE_CLASS + sizeof(sal_uInt16))
#define OFFSET_UIK 					(OFFSET_THIS_TYPE + sizeof(sal_uInt16))
#define OFFSET_DOKU 	   			(OFFSET_UIK + sizeof(sal_uInt16))
#define OFFSET_FILENAME				(OFFSET_DOKU + sizeof(sal_uInt16))

#define OFFSET_N_SUPERTYPES			(OFFSET_FILENAME + sizeof(sal_uInt16))
#define OFFSET_SUPERTYPES			(OFFSET_N_SUPERTYPES + sizeof(sal_uInt16))

#define OFFSET_CP_SIZE				(OFFSET_SUPERTYPES + sizeof(sal_uInt16))
#define OFFSET_CP 					(OFFSET_CP_SIZE + sizeof(sal_uInt16))

which allows to explain our header :

Field name Value
MAGIC 12 34 56 78
SIZE 00 00 01 46
MINOR_VERSION 00 00
MAJOR_VERSION 00 01
N_ENTRIES 00 06
TYPE_SOURCE 00 00
TYPE_CLASS 00 01
THIS_TYPE 00 01
UIK 00 02
DOKU 00 00
FILENAME 00 03
N_SUPERTYPES 00 00
SUPERTYPES 00 0B
CP_SIZE 00 00
CP 00 22

And so on... Is it important to go further ? Not at all, it was only to « play » a little. In fact we can directly recover this information with CoreReflection service (I am not absolutely sure of that). We give in the next section an overview in Ooobasic of this service.

How do we see the registries in OOoBasic ?

OooBasic allow many things and in particular to explore registry. Danny Brewer's code shows us how to work around ? We have a look at his code :

REM  *****  BASIC  *****
Sub Main 
  oReflection = createUnoService( "com.sun.star.reflection.CoreReflection" ) 
  oInfo = oReflection.forName( "nom.dannybrewer.test.XDannysCalcFunctions1" ) 
  aMethods = oInfo.getMethods() 
  For i = 0 To UBound( aMethods ) 
    oMethod = aMethods( i ) 
    Print oMethod.getName() 
  Next 
End Sub

We then create an idl file :

// IDL
#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/lang/XInitialization.idl>

module my_module
{

interface XSomething : com::sun::star::uno::XInterface
{
	long getCount();
	void setCount( [in] long nCount );
	long increment();
	long decrement();
};

service MyService
{
    interface XSomething;
};
};

With this IDL file, we create a rdb file and register this rdb file. Now OpenOffice.org works as if we have an add-on even if we have not written its code. We cannot launch this add-on (without its code !) but we can see it. We then modify the above Danny's program :

REM Listing 11 
REM  *****  BASIC  *****
'From Danny : http://www.oooforum.org/forum/viewtopic.php?t=8737 
Sub Main
  oReflection = createUnoService( "com.sun.star.reflection.CoreReflection" )
  oInfo = oReflection.forName( "my_module.XSomething" )
  aMethods = oInfo.getMethods()
  'XRay.XRay oInfo
  print  UBound( aMethods )+1 & " methods :  ****"
  For i = 0 To UBound( aMethods )
    oMethod = aMethods( i )
    Print oMethod.getName()
  Next

  aTypes = oInfo.getTypes()
  print  UBound( aTypes )+1 & " types :  ****"
  For i = 0 To UBound( aTypes )
    oType = aTypes( i )
    Print "Types : " + oType.getName()
  Next

  aInterfaces = oInfo.getInterfaces()
  print  UBound( aInterfaces )+1 & " interfaces :  ****"
  For i = 0 To UBound( aInterfaces )
    oInterface = aInterfaces( i )
    Print "Interfaces : " + oInterface.getName()
  Next
End Sub

launching this modified program produces :

7 methods : ****
queryInterface acquire release getCount setCount increment decrement
3 types : ****
Types : com.sun.star.reflection.XIdlClass
Types : com.sun.star.lang.XTypeProvider
Types : com.sun.star.uno.XWeak
0 Interfaces : ****

We can see among others the four methods given in the IDL file.

It is possible to retrieve more information on the methods for instance. If you want all the information given in the IDL file you can use OOoBasic code like that :

 For i = LBound( oMethods ) To UBound( oMethods )
      oMethod = oMethods( i )
      ' Check the method's interface to see if
      '  these aren't the droids you're looking for.
      sString = oMethod.getReturnType().getName() & " " & oMethod.getName() & "("
      parametersInfo = oMethod.getParameterInfos()
      if  UBound(parametersInfo) > 0 then
      for ii=0 to UBound(parametersInfo)
        if parametersInfo(ii).aMode = com.sun.star.reflection.ParamMode.IN Then
          stringType = "IN "
          elseif  parametersInfo(ii).aMode = com.sun.star.reflection.ParamMode.OUT Then
            stringType = "OUT "
        else
          stringType = "INOUT "
        end if      
        sString = sString & stringType  & ParametersInfo(ii).aType.getName() & " " & parametersInfo(ii).aName
        if ii < UBound(parametersInfo) Then sString = sString & ", "
      Next
      end if
      sString = sString & ")"
      ' something to do with sString here
 Next

To go further in C++ see XdlRefection Interface


See Also

Personal tools