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

From Apache OpenOffice Wiki
Jump to: navigation, search
m (Interfaces et services du defaultBootstrap_InitialComponentContext())
 
(3 intermediate revisions by 2 users not shown)
Line 8: Line 8:
 
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 [[UNO_registery_and_Bootstrapping#Playing_with_regview|chapitre 10.4]] pour voir une description de <code>regview</code>).
 
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 [[UNO_registery_and_Bootstrapping#Playing_with_regview|chapitre 10.4]] pour voir une description de <code>regview</code>).
  
{{Documentation/Tip|Conseil : dans une première lecture vous pouvez passer ce chapitre particulièrement si vous n'êtes pas intéressés par les [[FR/Documentation/Add-on|add-ons]] ou les [[FR/Documentation/Construire_des_composants|composants]]. Mais les add-ons ne sont pas les seuls programmes à utiliser la base de registre : les binaire exécutables ([[FR/Documentation/L%27automation_d%27OpenOffice.org_avec_un_binaire_ex%C3%A9cutable|chapitre 3]]) les utilisent aussi mais d'une manière un peu différente : nous discuterons de cela un peu plus tard.}}
+
{{Tip|Conseil : dans une première lecture vous pouvez passer ce chapitre particulièrement si vous n'êtes pas intéressés par les [[FR/Documentation/Add-on|add-ons]] ou les [[FR/Documentation/Construire_des_composants|composants]]. Mais les add-ons ne sont pas les seuls programmes à utiliser la base de registre : les binaire exécutables ([[FR/Documentation/L%27automation_d%27OpenOffice.org_avec_un_binaire_ex%C3%A9cutable|chapitre 3]]) les utilisent aussi mais d'une manière un peu différente : nous discuterons de cela un peu plus tard.}}
  
{{Documentation/Note|'''Service Managers''' UNO utilise le concept d'usine (factory) pour instancier les composants. Cette usine est appelée "service manager". Le service manager maintient une base de données des composants enregistrés. Votre application peut instancier et communiquer avec n'importe quel composant connu du service manager, quelque soit le langage d'implantation. La communication se fait à travers des appels d'interfaces spécifiées par des fichiers UNO-IDL. Voir ''' Creating a ServiceManager from a Given Registry File''' dans [[Documentation/DevGuide/WritingUNO/Special_Service_Manager_Configurations|Developer's Guide]].}}
+
{{Note|'''Service Managers''' UNO utilise le concept d'usine (factory) pour instancier les composants. Cette usine est appelée "service manager". Le service manager maintient une base de données des composants enregistrés. Votre application peut instancier et communiquer avec n'importe quel composant connu du service manager, quelque soit le langage d'implantation. La communication se fait à travers des appels d'interfaces spécifiées par des fichiers UNO-IDL. Voir ''' Creating a ServiceManager from a Given Registry File''' dans [[Documentation/DevGuide/WritingUNO/Special_Service_Manager_Configurations|Developer's Guide]].}}
  
 
=Comment utiliser la base de registres=
 
=Comment utiliser la base de registres=
Line 83: Line 83:
  
 
===Fonctionnement pratique du démarrage===
 
===Fonctionnement pratique du démarrage===
Pour voir ce qui se passe pendant le démarrage (bootstrap), nous allons examiner le répertoire <OpenOffice.org1.1_SDK>/LINUXexample.out/bin
+
Pour voir ce qui se passe pendant le démarrage (bootstrap), nous allons examiner le répertoire <OpenOffice.org_SDK>/LINUXexample.out/bin
 
où les binaires sont construit par le makefile :
 
où les binaires sont construit par le makefile :
 
* office_connect le binaire exécutable
 
* office_connect le binaire exécutable
Line 239: Line 239:
  
 
Si vous voulez utiliser cette façon pour démarrer votre code, regardez dans le répertoire <OOo_SDK>/examples/DevelopersGuide/ProfUno/SimpleBootstrap_cpp et commencez à modifier le code du fichier SimpleBootstrap_cpp.cxx sans changer le makefile.  
 
Si vous voulez utiliser cette façon pour démarrer votre code, regardez dans le répertoire <OOo_SDK>/examples/DevelopersGuide/ProfUno/SimpleBootstrap_cpp et commencez à modifier le code du fichier SimpleBootstrap_cpp.cxx sans changer le makefile.  
{{Documentation/Note|Cet exemple ne faisait pas partie des exemples du SDK 1.1.0. Je suppose donc que cette nouvelle fonction pour démarrer le code est apparue avec la version 2.X du SDK.}}
+
{{Note|Cet exemple ne faisait pas partie des exemples du SDK 1.1.0. Je suppose donc que cette nouvelle fonction pour démarrer le code est apparue avec la version 2.X du SDK.}}
  
 
Nous terminerons cette section en montrant le grand avantage de cette nouvelle fonction quant à sa simplicité. Montrons comment on obtient un document vide de type tableur, par exemple, à l'aide d'un arbre IDL :
 
Nous terminerons cette section en montrant le grand avantage de cette nouvelle fonction quant à sa simplicité. Montrons comment on obtient un document vide de type tableur, par exemple, à l'aide d'un arbre IDL :
Line 247: Line 247:
 
Quand nous parcourons cet arbre IDL, nous avons en final un document tableur vide ouvert.
 
Quand nous parcourons cet arbre IDL, nous avons en final un document tableur vide ouvert.
  
{{Documentation/Tip|
+
{{Tip|
 
A comparer avec la même chose réalisée avec <code>defaultBootstrap_InitialComponentContext()</code> [[Documentation/FR/L%27automation_d%27OpenOffice.org_avec_un_binaire_ex%C3%A9cutable#Ce_que_nous_avons_appris_dans_ce_chapitre|et présentée ici]].}}
 
A comparer avec la même chose réalisée avec <code>defaultBootstrap_InitialComponentContext()</code> [[Documentation/FR/L%27automation_d%27OpenOffice.org_avec_un_binaire_ex%C3%A9cutable#Ce_que_nous_avons_appris_dans_ce_chapitre|et présentée ici]].}}
  
{{Documentation/Note|Il semble que ce nouveau mode de démarrage ne nécessite plus de fichier rdb. En tout cas je n'en ai pas trouvé, et le makefile ne semble pas en manipuler.}}
+
{{Note|Il semble que ce nouveau mode de démarrage ne nécessite plus de fichier rdb. En tout cas je n'en ai pas trouvé, et le makefile ne semble pas en manipuler.}}
  
 
=Visualiser la base de registre=
 
=Visualiser la base de registre=
 
Voir [[Documentation/DevGuide/WritingUNO/Deployment_Options_for_Components|Deployment Options for Components]] and [[Documentation/DevGuide/WritingUNO/Register_Component_File|Register Component File]] dans le Developer's Guide.
 
Voir [[Documentation/DevGuide/WritingUNO/Deployment_Options_for_Components|Deployment Options for Components]] and [[Documentation/DevGuide/WritingUNO/Register_Component_File|Register Component File]] dans le Developer's Guide.
 
  
 
=Comment manipuler la base de registre en C++ ?=
 
=Comment manipuler la base de registre en C++ ?=
Line 686: Line 685:
 
=Court-circuiter la base de registre=
 
=Court-circuiter la base de registre=
 
Il est possible de se passer de la base de registre sous Windows avec le langage OOobasic. En effet on peut appeler directement une fonction d'une dll sans enregistrer cette dernière.
 
Il est possible de se passer de la base de registre sous Windows avec le langage OOobasic. En effet on peut appeler directement une fonction d'une dll sans enregistrer cette dernière.
{{Documentation/Tip|
+
{{Tip|
 
* A étudier s'il est possible d'appeler directement une DLL non enregistrée à partir du C++ en passant par OpenOffice.org.
 
* A étudier s'il est possible d'appeler directement une DLL non enregistrée à partir du C++ en passant par OpenOffice.org.
 
* Voir comment il est possible d'étendre cette fonctionnalité avec les librairies dynamiques sous Linux.}}
 
* Voir comment il est possible d'étendre cette fonctionnalité avec les librairies dynamiques sous Linux.}}

Latest revision as of 21:13, 14 July 2018

OpenOffice.org peut être étendu, 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 qui utilise les 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 donc 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-programme 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.4 pour voir une description de regview).

Tip.png Conseil : dans une première lecture vous pouvez passer ce chapitre particulièrement si vous n'êtes pas intéressés par les add-ons ou les composants. Mais les add-ons ne sont pas les seuls programmes à utiliser la base de registre : les binaire exécutables (chapitre 3) les utilisent aussi mais d'une manière un peu différente : nous discuterons de cela un peu plus tard.


Documentation note.png Service Managers UNO utilise le concept d'usine (factory) pour instancier les composants. Cette usine est appelée "service manager". Le service manager maintient une base de données des composants enregistrés. Votre application peut instancier et communiquer avec n'importe quel composant connu du service manager, quelque soit le langage d'implantation. La communication se fait à travers des appels d'interfaces spécifiées par des fichiers UNO-IDL. Voir Creating a ServiceManager from a Given Registry File dans Developer's Guide.

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)

Bootstrap est traduit généralement par programme d'amorce en tout cas dans mon dictionnaire. Je le traduirai par démarrage ou code de démarrage dans cette section. Je garderai aussi parfois la terminologie anglaise.

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

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.

Interfaces et services du defaultBootstrap_InitialComponentContext()

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

defaultBootstrap_InitialComponentContext() est une fonction toute faite qui nous permet d'avoir une interface com.sun.star.uno.XComponentContext comme déjà expliqué ici. Cette interface contient une méthode "getServiceManager" que l'on utilise pour obtenir le service manager (com.sun.star.lang.XMultiComponentFactory). C'est une interface qui elle aussi, parmi d'autres, contient la méthode "createInstanceWithContext" que l'on utilise aussi avec comme paramètres la chaîne de caractères "com.sun.star.bridge.UnoUrlResolver" et notre variable de type com.sun.star.uno.XComponentContext que l'on a déjà obtenue. On peut ainsi poursuivre le dessin jusqu'au bout, ce qu'on laisse comme exercice au lecteur (voir aussi les interfaces com.sun.star.uno.XInterface, com.sun.star.bridge.XUnoUrlResolver et com.sun.star.lang.XMultiServiceFactory). Notez que la double flèche entre les rectangles XInterface est là pour désigner que l'on utilise la même variable dans les deux cas.

Puisque getServiceManager est une méthode qui retourne un type XMultiComponentFactory, il nous est très difficile de prévoir les services accessibles à partir de la variable de type XMultiComponentFactory. C'est un problème récurrent que j'ai déjà tenté d'expliquer ici. En utilisant un outil d'introspection, j'ai pu trouver deux services :

com.sun.star.lang.RegistryServiceManager
com.sun.star.lang.MultiServiceFactory

et 11 interfaces

******** Types - Interfaces : 11
com.sun.star.lang.XComponent
com.sun.star.uno.XWeak
com.sun.star.lang.XTypeProvider
com.sun.star.beans.XPropertySet
com.sun.star.container.XContentEnumerationAccess
com.sun.star.container.XSet
com.sun.star.lang.XUnoTunnel
com.sun.star.lang.XInitialization
com.sun.star.lang.XServiceInfo
com.sun.star.lang.XMultiComponentFactory
com.sun.star.lang.XMultiServiceFactory

Voir donc aussi les services com.sun.star.lang.RegistryServiceManager et com.sun.star.lang.MultiServiceFactory ainsi que toutes les interfaces correspondantes com.sun.star.lang.XComponent, com.sun.star.uno.XWeak, com.sun.star.lang.XTypeProvider, com.sun.star.beans.XPropertySet, com.sun.star.container.XContentEnumerationAccess, com.sun.star.container.XSet, com.sun.star.lang.XUnoTunnel, com.sun.star.lang.XInitialization, com.sun.star.lang.XServiceInfo, com.sun.star.lang.XMultiComponentFactory et com.sun.star.lang.XMultiServiceFactory. Avec cela vous êtes paré pour aller plus loin dans votre recherche sur les services et interfaces, mais je ne vous y accompagne pas.

Fonctionnement pratique du démarrage

Pour voir ce qui se passe pendant le démarrage (bootstrap), nous allons examiner le répertoire <OpenOffice.org_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 signification de la variable SYSBINDIR et des autres peut être trouvée dans le Developer's Guide.

La construction de ces fichiers nous en apprendra peut-être un peu plus. Nous décrivons la chaîne de compilation (sous forme textuelle) 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

mais montre une dépendance au fichier office_connectrc. Maintenant un petit test pour voir.

  • le office_connectrc est chargé automatiquement au démarrage. Un moyen de tester est de renommer ce fichier, ce qui a pour effet de donner 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 qui garde l'information de la place du fichier office_connect.rdb qui sera chargé.

La création de office_connect.rdb

Nous allons dans le répertoire de création de ce fichier (soit pour nous <OOoSDK>/LINUXexample.out/bin) et lançons la commande d'exploration regview :

 ../../linux/bin/regview office_connect.rdb /IMPLEMENTATIONS

qui nous affiche :

Registry "file:///home/smoutou/openoffice.org2.3_sdk/LINUXexample.out/bin/office_connect.rdb":
/IMPLEMENTATIONS
 / com.sun.star.comp.io.Connector
   / UNO
     / ACTIVATOR
       Value: Type = RG_VALUETYPE_STRING
              Size = 34
              Data = "com.sun.star.loader.SharedLibrary"

     / SERVICES
       / com.sun.star.connection.Connector
     / LOCATION
       Value: Type = RG_VALUETYPE_STRING
              Size = 17
              Data = "connector.uno.so"

 / com.sun.star.comp.remotebridges.Bridge.various
   / UNO
     / ACTIVATOR
       Value: Type = RG_VALUETYPE_STRING
              Size = 34
              Data = "com.sun.star.loader.SharedLibrary"

     / SERVICES
       / com.sun.star.bridge.UrpBridge
       / com.sun.star.bridge.Bridge
       / com.sun.star.bridge.IiopBridge
     / LOCATION
       Value: Type = RG_VALUETYPE_STRING
              Size = 20
              Data = "remotebridge.uno.so"

 / com.sun.star.comp.remotebridges.BridgeFactory
   / UNO
     / ACTIVATOR
       Value: Type = RG_VALUETYPE_STRING
              Size = 34
              Data = "com.sun.star.loader.SharedLibrary"

     / SERVICES
       / com.sun.star.bridge.BridgeFactory
     / LOCATION
       Value: Type = RG_VALUETYPE_STRING
              Size = 17
              Data = "bridgefac.uno.so"

 / com.sun.star.comp.bridge.UnoUrlResolver
   / UNO
     / ACTIVATOR
       Value: Type = RG_VALUETYPE_STRING
              Size = 34
              Data = "com.sun.star.loader.SharedLibrary"

     / SERVICES
       / com.sun.star.bridge.UnoUrlResolver
     / LOCATION
       Value: Type = RG_VALUETYPE_STRING
              Size = 18
              Data = "uuresolver.uno.so"

On voit apparaître un certain nombre de librairies dynamiques (extensions .uno.so sous linux). Il est intéressant de se demander comment elles sont apparues ? D'abord office_connect.rdb est créé par la commande :

<OOo_sdk>/linux/bin/regmerge <OOo_sdk>/LINUXexample.out/bin/office_connect.rdb <OOo>/program/types.rdb

puis les librairies sont enregistrées une à une par :

<OOo_sdk>/linux/bin/regcomp -register -r <OOo_sdk>/LINUXexample.out/bin/office_connect.rdb -c connector.uno.so
<OOo_sdk>/linux/bin/regcomp -register -r <OOo_sdk>/LINUXexample.out/bin/office_connect.rdb -c remotebridge.uno.so
<OOo_sdk>/linux/bin/regcomp -register -r <OOo_sdk>/LINUXexample.out/bin/office_connect.rdb -c bridgefac.uno.so
<OOo_sdk>/linux/bin/regcomp -register -r <OOo_sdk>/LINUXexample.out/bin/office_connect.rdb -c uuresolver.uno.so

A ce point, notre fichier office_connect.rdb est complet et je vous conseille vivement d'aller voir la chaîne de compilation et de mettre en correspondance ce qui est décrit ici et le dessin correspondant.

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

L'exemple documentLoader (voir <OpenOffice.org_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é. Il est réalisé avec l'utilitaire regmerge. Par rapport à l'exemple précédent, 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"

Ce démarrage nécessite aussi la présence d'un fichier rdb. Son nom est ici DocumentLoader.rdb et il est très similaire à office_connect.rdb.

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

Si vous voulez utiliser cette façon pour démarrer votre code, regardez dans le répertoire <OOo_SDK>/examples/DevelopersGuide/ProfUno/SimpleBootstrap_cpp et commencez à modifier le code du fichier SimpleBootstrap_cpp.cxx sans changer le makefile.

Documentation note.png Cet exemple ne faisait pas partie des exemples du SDK 1.1.0. Je suppose donc que cette nouvelle fonction pour démarrer le code est apparue avec la version 2.X du SDK.

Nous terminerons cette section en montrant le grand avantage de cette nouvelle fonction quant à sa simplicité. Montrons comment on obtient un document vide de type tableur, par exemple, à l'aide d'un arbre IDL :

NewBootstrap.png

Quand nous parcourons cet arbre IDL, nous avons en final un document tableur vide ouvert.

Tip.png

A comparer avec la même chose réalisée avec defaultBootstrap_InitialComponentContext() et présentée ici.


Documentation note.png Il semble que ce nouveau mode de démarrage ne nécessite plus de fichier rdb. En tout cas je n'en ai pas trouvé, et le makefile ne semble pas en manipuler.

Visualiser la base de registre

Voir Deployment Options for Components and Register Component File dans le Developer's Guide.

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 aussi les services com.sun.star.registry.ImplementationRegistration et com.sun.star.loader.SharedLibrary)

//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 examination plus approfondie 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

Outils pour la base de registre en C++

Introduction

Je veux retrouver et décoder l'information binaire contenue dans la base de registre OpenOffice. Mon choix pour cela s'est porté sur l'interface XInterface pour des tests. Je me suis demandé s'il était possible de retrouver toute l'information donnée par l'outil regview :

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

Code C++ pour retrouver l'information à partir du binaire

Regardez le listing ci-dessous pour apprendre comment on peut retrouver l'information importante à partir du binaire contenue dans la base de registre OpenOffice.

//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;
		}
....
// avec la 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"); 
}

Un examen attentif sur le listing ci-dessus montre que l'on transforme du binaire en un format qui rappelle l'ancien outil DEBUG de nos vieux DOS.

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

On voit ainsi qu'il est possible de comprendre comment ces octets sont constitués pour contenir l'information que l'on recherche, mais cela nous prendrait beaucoup de temps pour aller plus en avant.

Je préfère chercher dans le code source d'OpenOffice (c'est l'intérêt d'en disposer) et finalement je trouve ce qu'il ma faut dans : « OOB680_m5/registry/source/reflcnst.hxx »

Examen attentif du code source OOo

Par exemple avant chaque nom on voit un « 00 0C ». Il est effectivement défini dans le fichier reflcnst.hxx comme :

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

qui nous apprend que c'est un tag d'information de type CP_TAG_UTF8_NAME. Si nous voulons décoder l'entête, nous utilisons cet extrait :

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

qui nous permet d'expliquer notre entête :

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

Et ainsi de suite... Est-il important d'aller plus loin ? Pas du tout, j'ai fait tout cela pour m'amuser un peu. En fait on peut retrouver directement cette information avec le service CoreReflection. Je ne suis pas absolument sûr de cela car il est difficile de savoir comment les services d'introspection retrouvent leur information : à partir de la base de registre ou autrement ?

Court-circuiter la base de registre

Il est possible de se passer de la base de registre sous Windows avec le langage OOobasic. En effet on peut appeler directement une fonction d'une dll sans enregistrer cette dernière.

Tip.png
  • A étudier s'il est possible d'appeler directement une DLL non enregistrée à partir du C++ en passant par OpenOffice.org.
  • Voir comment il est possible d'étendre cette fonctionnalité avec les librairies dynamiques sous Linux.


Retour à la page d'accueil

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

Voir aussi

Personal tools