Difference between revisions of "FR/Documentation/Base de registres"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (Démarrage UNO/C++ via Bootstrap_InitialComponentContext())
Line 109: Line 109:
 
</pre>
 
</pre>
  
 +
==la nouvelle fonction ::cppu::bootstrap() ==
 +
Comme expliqué dans le [[Documentation/DevGuide/ProUNO/C%2B%2B/C%2B%2B_Language_Binding|Developer's Guide]] une nouvelle fonction est disponible maintenant pour le bootstrapping. Regardez le code correspondant dans  [[Documentation/DevGuide/ProUNO/C%2B%2B/Transparent_Use_of_Office_UNO_Components|Developer's Guide]]. J'ai aussi trouvé dans le forum [http://www.oooforum.org/forum/viewtopic.phtml?t=80624 oooForum] l'extrait de code suivant qui montre comment cela fonctionne.
  
 +
<source lang="cpp">
 +
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);
 +
</source>
  
 
=Comment manipuler la base de registre en C++ ?=
 
=Comment manipuler la base de registre en C++ ?=

Revision as of 20:29, 27 February 2009

OpenOffice.org peut être étendue, on peut lui ajouter des fonctionnalités en OooBasic, en C++, en Java en Python... Ces fonctionnalités ajoutées sont appelées add-on et l'on peut se demander comment OpenOffice.org peut connaître quelque chose sur ces codes. Ceci se fait à l'aide de la base de registre UNO à l'aide des outils regview, regcomp, regmerge et idlc.

Pourquoi une base de registre UNO ?

Il est très commun pour un programmeur de réaliser un programme qui utilise une librairie statique. Si la librairie est dynamique, le problème de l'édition de lien est laissé au système d'exploitation. Ce système d'exploitation a à savoir si la librairie est déjà chargée en mémoire et dans le cas contraire où est le fichier correspondant. Mais que se passe-t-il si vous avez déjà un fichier binaire exécutable et que vous désiriez lui ajouter des fonctionnalités avec des librairies que vous créez ? Cela peut être réalisé avec Openoffice.org comme déjà mentionné. La première chose est qu'il est impossible pour votre binaire exécutable OpenOffice.org de connaître à l'avance le nom de la librairie que vous allez réaliser(c'est un nom que vous avez choisi).Il faut dons un mécanisme à OpenOffice.org pour retrouver ce nom et d'autres informations : ceci est le principal objectif de la base de registre UNO. Le nom des librairies n'est pas la seule information indispensable à gérer par cette base de registre. Si l'on imagine que l'on peut étendre avec plusieurs librairies, il faudra savoir que le sous-brogramme bidon1 vient de telle librairie et que bidon2 vient de telle autre. En OpenOffice.org l'élément central est l'interface et donc l'information pertinente est que telle interface se trouve dans telle librairie...

La base de registre UNO utilise des fichiers binaires d'extension rdb. Ce format binaire est difficile à lire par l'homme et un outil pour faciliter la lecture est donc fournit avec le SDK (aller au chapitre 10.3 pour voir une description de regview).

Template:Documentation/Tip

Template:Documentation/Note

Comment utiliser la base de registres

La documentation concernant la base de registre UNO existe et peut être consultée à l'adresse suivante : http://udk.openoffice.org/common/man/tutorial/uno_registries.html On peut aussi trouver de l'information à : http://www.ooomacros.org/dev.php sur

  • 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

De mon point de vue la manière la plus simple d'ajouter de l'information dans la base de registres est de modifier le fichier unorc (sous linux) ou uno.ini (sous Windows). Vous devez mettre votre fichier your_library.uno.rdb dans le répertoire <OOo>/program, et éditer /modifier le fichier <OOo>/program/unorc (sous linux) en ajoutant ce que j'ai coloré en rouge ci-dessous :

#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

Il ne faut pas oublier d'enregistrer la position de votre fichier your_library.uno.so dans le fichier your_library.uno.rdb. Cela est réalisé avec l'outil regcomp :

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

Un autre moyen d'obtenir ce résultat est d'utiliser pkgchk ou unopkg depuis OOo2.X

Le démarrage (Bootstrap)

Bootstrapping peut être défini en disant que c'est un moyen d'obtenir le service manager. Nous présentons maintenant deux moyens de démarrage (bootstraping).

Démarrage UNO/C++ via defaultBootstrap_InitialComponentContext()

Nous avons déjà décrit cette méthode parce qu'elle concerne les exemples classiques du SDK avec lesquels nous avons commencés (voir <OpenOffice.org1.1_SDK>/examples/DevelopersGuide/ProfUNO/CppBinding). Nous donnons ici deux vues différentes pour expliquer comment cela fonctionne.

Premièrement avec la figure ci-dessous, un petit rappel sur la manière de le programmer. C'est facile de voir que la première instruction C++ correspondante est :

//C++
defaultBootstrap_InitialComponentContext();

Mais, même les détails de la figure ne nous permettent pas de voir comment cela fonctionne et en particulier le rapport avec la base de registre. C'est tout simplement parce que la figure ci-dessous n'est qu'un point de vue de programmeur C++/Java.

Ch4Fig1bootstrap.png

Pour voir ce qui se passe pendant le démarrage (bootstrap), nous allons examiner le répertoire <OpenOffice.org1.1_SDK>/LINUXexample.out/bin où les binaires sont construit par le makefile :

  • office_connect le binaire exécutable
  • office_connectrc : fichier qui contient :
UNO_TYPES=$SYSBINDIR/office_connect.rdb
UNO_SERVICES=$SYSBINDIR/office_connect.rdb
  • office_connect.rdb

La construction de ces fichiers nous en apprendra peut-être un peu plus. Nous donnons la chaîne de compilation de office_connect qui nous montre comment office_connect.rdb est construit :

  • à l'aide d'un regmerge partant du fichier types.rdb
  • à l'aide de regcomp pour enregistrer les fichiers de librairies dynamiques (uno.so ou uno.dll).

Et maintenant il nous faut apprendre comment le fichier office_connect.rdb est utilisé (ligne correspondante du fichier makefile) : la ligne

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

est transformée en

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

qui montre une référence au fichier office_connect.rdb. Maintenant un petit test pour voir.

  • le office_connectrc est chargé automatiquement au démarrage. Un moyen de tester est de renommer ce fichier qui donne le message d'erreur
make: *** [office_connect.run] Erreur 134
  • renommer seulement office_connect.rdb donne la même erreur :
make: *** [office_connect.run] Erreur 134
  • renommer office_connect.rdb comme office_connect2.rdb en changeant le contenu de office_connectrc, comme montré ci-dessous marche correctement.
UNO_TYPES=$SYSBINDIR/office_connect2.rdb
UNO_SERVICES=$SYSBINDIR/office_connect2.rdb

Conclusion : nous avons trouvé comment cela fonctionne : quand vous lancez un binaire il charge automatiquement office_connectrc et met le fichier office_connect2.rdb à la bonne place.

Démarrage UNO/C++ via Bootstrap_InitialComponentContext()

L'exemple documentLoader (voir <OpenOffice.org1.1_SDK>/examples/cpp/DocumentLoader) utilise un autre moyen de démarrage. Nous voulons le décrire maintenant. De nouveau nous commençons par le point de vue du programmeur en figure ci-dessous.

SecondBootstrap.png

Dans ce deuxième cas nous voyons clairement que le fichier DocumentLoader.rdb est necessaire et chargé. La seule différence est avec la base de registre. On trouve encore un fichier rdb mais pas de fichier rc. La conséquence est la présence d'une commande spécifique regcomp pour l'enregistrement du binaire exécutable.

Cet exemple ne peut pas fonctionner si OpenOffice.org n'est pas lancé. Dans cet exemple, l'interaction entre OpenOffice.org et some.bin se fait à travers le réseau. En d'autres mots, le binaire et OpenOffice peuvent s'exécuter sur deux ordinateurs différents. Vous devez exécuter OpenOffice.org en lui demandant d'attendre une connexion UNO (ici seulement en provenance de localhost) :

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

la nouvelle fonction ::cppu::bootstrap()

Comme expliqué dans le Developer's Guide une nouvelle fonction est disponible maintenant pour le bootstrapping. Regardez le code correspondant dans Developer's Guide. J'ai aussi trouvé dans le forum oooForum l'extrait de code suivant qui montre comment cela fonctionne.

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);

Comment manipuler la base de registre en C++ ?

Ce n'est pas très difficile de trouver un exemple qui manipule la base de registre en C++. Comme premier exemple, on peut prendre le counter example. Cet exemple est intéressant en ce qu'il est composé par deux fichiers : counter.cxx et countermain.cxx. Counter.cxx est compilé en counter.uno.so (counter.uno.dll sous windows) et un fichier counter.uno.rdb est créé. Comme déjà montré, ce fichier est pour la base de registre.

Mais ce qui est nouveau, c'est que le deuxième programme est chargé de l'enregistrement : countermain.cxx. Ainsi, en lisant ce fichier on a la possiblité d'examiner comment fait-on cela en C++ (voir ci-après)

//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
			);

Une autre examination du fichier countermain.cxx nous montre que le bootstrap est réalisé comme dans l'exemple du DocumentLoader déjà cité et donc fournit une interface XComponentContext (xContext) et XMultiComponentFactory (xMgr) utilies pour la manipulation de la base de registre.

On ne peut pas continuer sans se demander ce qu'est l'interface XImplementationRegistration  ? On donne de nouveau le fichier IDL :

// 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 );
 
};
}; }; }; };

On voit, parmi d'autres, la méthode que l'on veut tester : getImplementations. On ajoute alors le code suivant dans le 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);
		}

qui affiche :

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

Signification : si l'on utilise le service SharedLibrary pour charger counter.uno.so, j'aurai comme nom d'implementation (implementation name) « com.sun.star.comp.example.cpp.Counter ». Cette information est stockée dans la base de registre comme indiqué dans le Developpers Guide. Pour notre exemple :

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

donne le résultat :

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"

où l'association entre le nom « com.sun.star.comp.example.cpp.Counter » et sa librairie correspondante (sous Linux) « counter.uno.so » est faite.

C'est possible d'avoir le nom du service :

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]$

Et voici le résultat pour « foo.Counter ».

On veut retrouver l'information du listing 6 mais avec C++.De nouveau des modifications dans le fichier countermain.cxx s'imposent (juste après la dernière ligne du listing 2) comme montré ci-dessous :

//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();

qui affiche

-- 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

La base de registres et OOoBasic

OooBasic permet beaucoup de choses et en particulier une exploration de la base de registre. Le code de Danny Brewer présenté ici : http://www.oooforum.org/forum/viewtopic.php?t=8737 nous montre comment ? Examinons un peu plus en détail ce code :

'Listing 160 Code d'exploration de la base de registre en OOoBasic
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

puis nous créons un fichier IDL :

//Listing 161 Fichier IDL d'exemple
// 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;
};
};

Avec ce fichier IDL il nous est possible de créer un fichier rdb et de l'enregistrer dans la base de registre. Maintenant OpenOffice.org fonctionne comme si nous avions une interface supplémentaire même si l'on n'a pas encore écrit le code correspondant. Evidemment, il nous est impossible d'utiliser ce service puis qu'il n'y a pas ded code corrrespondant, mais on peut le voir. Pour cela on modifie légèrement le code de Danny :

'Listing 162
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

qui lancé produit l'affichage suivant :

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 : ****

où l'on peut voir parmi d'autres choses les quatre méthodes données dans le fichier IDL. Template:Documentation/Note

Retour à la page d'accueil

Page d'accueil du développement C++ à l'aide du SDK

Voir aussi

Personal tools