Accès au registre Windows en utilisant les XPCOM

Cette page vient d'être traduite, mais elle a besoin d'un relecteur différent du traducteur. Pensez également à toujours vérifier le contenu avec sa toute dernière version en anglais.

Introduction

Lors de l'implémentation de fonctionnalités propres à Windows, il est souvent utile d'accéder au registre Windows pour obtenir des informations concernant l'environnement ou d'autres programmes installés. À cette fin, il existe des interfaces XPCOM pour lire et écrire des données dans le registre. Cet article vous montre comment utiliser les interfaces disponibles dans plusieurs produits Mozilla.

Les exemples dans ce document sont tous écrits en JavaScript via les XPCOM.

Support dans Firefox 1.5 et suivant

Dans Firefox 1.5, une nouvelle API a été ajoutée -- nsIWindowsRegKey -- pour fournir des fonctionnalités étendues sur le registre. L'interface est très proche de l'API Windows, mais avec quelques détails de bas niveau dont vous devez tenir compte. Si vous écrivez une extension qui ne supporte que Firefox 1.5 et suivante, vous n'avez qu'à lire cette section.

Un simple exemple

Voici un simple exemple montrant comment lire le ProductID Windows :

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
         "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
         wrk.ACCESS_READ);
var id = wrk.readStringValue("ProductId");
wrk.close();

Cet exemple, bien que simple, montre plusieurs choses importantes au sujet de l'interface. Premièrement, vous devez utiliser createInstance() pour obtenir un objet implémentant cette interface, pas getService(). Deuxièmement, vous devez appeler open() sur la clef avant d'essayer de lire une valeur.

Notez dans l'appel open() que la clef racine à utiliser est spécifiée en utilisant les constantes disponibles dans l'interface nsIWindowsRegKey. Dans ce cas, il s'agit de ROOT_KEY_LOCAL_MACHINE correspondant au HKEY_LOCAL_MACHINE du registre Windows. Notez également que le chemin de la clef a des antislashes échappés, ce qui est une nécessité avec les constantes textes JavaScript et C++.

Les droits d'accès souhaités sont spécifiés par une constante nommée de l'interface, dans cet exemple, il s'agit de ACCESS_READ. Ceci est très important lorsque vous gérez des comptes non administrateurs avec des privilèges restreints.

La valeur est lue avec readStringValue(). Vous devez spécifier quel type de données vous vous attendez à lire, ce qui sera détaillé plus tard. Finalement, notez que vous devez fermer la clef lorsque vous avez fini pour éviter une perte de ressources système.

Ouvrir des clefs du registre

Avant de faire quoi que ce soit avec une clef du registre, vous devez ouvrir au préalable la clef qui vous intéresse. L'exemple ci-dessus vous montre l'utilisation de la méthode open(). Si vous souhaitez créer une nouvelle clef, vous pouvez utiliser la méthode create() qui prend les mêmes paramètres que open(). Notez que l'appel de create() sur une clef existante ne constitue pas une erreur, et aura le même résultat que l'appel de open().

Ces deux méthodes prennent un clef racine en premier paramètre. En JavaScript, vous devez utiliser les constantes nommées de l'interface pour ce paramètre. Ces constantes sont :

  • ROOT_KEY_CLASSES_ROOT — Correspond à HKEY_CLASSES_ROOT
  • ROOT_KEY_CURRENT_USER — Correspond à HKEY_CURRENT_USER
  • ROOT_KEY_LOCAL_MACHINE — Correspond à HKEY_LOCAL_MACHINE

Le deuxième paramètre pour open() et create() est le chemin vers la clef. Comme noté dans l'exemple ci-dessus, vous devrez échapper les antislashes de la chaîne de caractères.

Le troisième paramètre pour open() et create() est le mode d'accès. Il est spécifié par une combinaison binaire de drapeaux définis par l'interface. Vous devrez lire la documentation de l'interface pour une explication complète, mais voici les trois modes les plus utilisés :

  • ACCESS_READ — pour lire des valeurs, énumérer des clefs, et recevoir des notification
  • ACCESS_WRITE — pour définir des valeurs et créer des sous-clefs
  • ACCESS_ALL — accès pour toutes les opérations

En complément de open() et create(), il existe les méthodes openChild() et createChild(). Vous pouvez appeler ces méthodes sur une clef du registre déjà ouverte pour ouvrir une clef enfant. Ces méthodes prennent un chemin relatif et un mode d'accès comme paramètres, et renvoient un nouvel objet implémentant nsIWindowsRegKey. Voici un autre exemple simple, mais utilisant openChild() :

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
         "SOFTWARE\\Microsoft",
         wrk.ACCESS_READ);
var subkey = wrk.openChild("Windows\\CurrentVersion", wrk.ACCESS_READ);
var id = subkey.readStringValue("ProductId");
subkey.close();
wrk.close();

Une fois que vous avez ouvert une clef du registre, vous pouvez commencer à vous en servir.

Lecture des valeurs du registre

Probablement l'action la plus commune associé au registre Windows est la lecture des valeurs. L'exemple simple ci-dessus montre comment lire une valeur texte existante. Cependant, les valeurs du registre Windows peuvent être de plusieurs types, donc vous devez être certain du type de la valeur à lire. Vous pouvez tester le type d'une valeur en utilisant la méthode getValueType(). Cette méthode renvoie un entier indiquant le type de donnée de la valeur. Les types de données supportés sont définis par les constantes nommées de l'interface comme ceci :

  • TYPE_NONE — Probablement pas utile
  • TYPE_STRING — Une chaîne de caractères Unicode
  • TYPE_BINARY — Donnée binaire
  • TYPE_INT — Un entier de 32 bit
  • TYPE_INT64 — Un entier de 64 bit

Chacune de ces valeurs (excepté TYPE_NONE) possède une méthode correspondante pour lire la valeur :

  • readStringValue()
  • readBinaryValue()
  • readIntValue()
  • readInt64Value()

Comme JavaScript est un langage typé dynamiquement, vous pouvez utiliser le code suivant pour gérer tous les types de données. Dans cette fonction, wrk suppose être un nsIWindowsRegKey déjà ouvert.

function readRegistryValue(wrk, value)
{
  switch (wrk.getValueType(value)) {
    case wrk.TYPE_STRING:
      return wrk.readStringValue(value);
    case wrk.TYPE_BINARY:
      return wrk.readBinaryValue(value);
    case wrk.TYPE_INT:
      return wrk.readIntValue(value);
    case wrk.TYPE_INT64:
      return wrk.readInt64Value(value);
  }
  // type inconnu
  return null;
}

Écriture de valeurs dans le registre

L'écriture de valeurs dans le registre est similaire à la lecture. Pour chaque type de données supporté, il existe une méthode write*Value() complémentaire à la méthode read*Value(). N'oubliez pas que si vous écrivez une nouvelle valeur, vous devrez créer (create()) la clef parent en premier. Cet exemple montre la création d'une nouvelle valeur texte :

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.create(wrk.ROOT_KEY_CURRENT_USER,
           "SOFTWARE\\MDC\\Test",
           wrk.ACCESS_WRITE);
wrk.writeStringValue("ValeurTest", "Bonjour le monde !");
wrk.close();

Test d'existence des clefs et valeurs

Avant de tenter de lire une valeur ou d'ouvrir une clef enfant, vous devriez vérifier d'abord si elle existe. L'interface nsIWindowsRegKey fournit deux méthodes pour cela—hasValue() et hasChild()—comme montré dans cet exemple :

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
           "SOFTWARE\\Microsoft",
           wrk.ACCESS_READ);
if (wrk.hasChild("Windows")) {
  var subkey = wrk.openChild("Windows\\CurrentVersion", wrk.ACCESS_READ);
  var id;
  if (subkey.hasValue("ProductId"))
    id = subkey.readStringValue("ProductId");
  subkey.close();
}
wrk.close();

Énumération de clefs et valeurs du registre

Dans certaines situations, vous souhaitez énumérer un certain nombre de clefs ou valeurs dont vous ne connaissez pas les noms. L'interface nsIWindowsRegKey fournit les propriétés et méthodes childCount, getChildName(), valueCount, et getValueName() pour énumérer respectivement des clefs et des valeurs. Vous pouvez utiliser ces méthodes pour lire une liste de valeurs ou accéder récursivement à une branche du registre. Cet exemple lit tous les programmes de démarrage dans une clef du registre :

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
         "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
         wrk.ACCESS_READ);
for (var i=0; i<wrk.valueCount; i++) {
  var name  = wrk.getValueName(i);
  var value = readRegistryValue(wrk, name);
  // faire ici quelque chose d'intéressant...
}
wrk.close();

Pour plus de simplicité, cet exemple suppose que la fonction readRegistryValue() définie ci-dessus existe.

Suppression de clefs et valeurs du registre

Pour supprimer des clefs enfants et des valeurs du registre, vous pouvez utiliser les méthodes removeChild() et removeValue(). removeChild() supprime une clef enfant et toutes ses valeurs, mais échouera si la clef contient une autre clef enfant. Dans ce cas, vous devrez énumérer manuellement tous les enfants, et les effacer individuellement. Cet exemple vous montre comment effacer récursivement une clef de registre et tous ses enfants. À utiliser avec précaution !

function removeChildrenRecursive(wrk)
{
  // nous décomptons car la suppression s'effectue à la fin
  for (var i = wrk.childCount - 1; i >= 0; i--) {
    var name   = wrk.getChildName(i);
    var subkey = wrk.openChild(name, wrk.ACCESS_ALL);
    removeChildrenRecursive(subkey);
    subkey.close();
    wrk.removeChild(name);
  }
}

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_CURRENT_USER,
         "SOFTWARE\\MDC\\Test",
         wrk.ACCESS_ALL);
removeChildrenRecursive(wrk);
wrk.close();

Surveillance des clefs du registre

Si vous souhaitez savoir si une clef de registre a été modifiée depuis la dernière vérification, vous pouvez utiliser les méthodes startWatching(), stopWatching(), et hasChanged(). Vous devez appeler startWatching() pour la clef à surveiller. La méthode ne prend qu'un paramètre, un booléen indiquant si les clefs enfants doivent ou non être également surveillées. Ensuite, vous appelez hasChanged() pour déterminer si vous devez ou non relire la valeur. L'appel de hasChanged() réinitialise automatiquement la surveillance, donc si la méthode renvoie true, c'est qu'il y a eu des modifications. Cet exemple montre un cache trivial de registre sur une seule clef :

var cache = {};

function readRegistryValueNoCache(wrk, value)
{
  switch (wrk.getValueType(value)) {
    case wrk.TYPE_STRING:
      return wrk.readStringValue(value);
    case wrk.TYPE_BINARY:
      return wrk.readBinaryValue(value);
    case wrk.TYPE_INT:
      return wrk.readIntValue(value);
    case wrk.TYPE_INT64:
      return wrk.readInt64Value(value);
  }
  // type inconnu
  return null;
}

function readRegistryValue(wrk, value)
{
  if (wrk.hasChanged()) {
    // vide le cache
    cache = {};
  }

  if (value in cache) {
    return cache[value];
  }
  
  cache[value] = readRegistryValueNoCache(wrk, value);
  return cache[value];
}

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
                    .createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
         "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
         wrk.ACCESS_READ);
wrk.startWatching(false); // surveille seulement les valeurs sur cette clef, pas les clefs enfants
var id = readRegistryValue(wrk, "ProductId");
/* plus tard, vous pouvez relire de nouveau, 
   et vous obtiendrez la valeur du cache 
   à moins que cette valeur a été modifiée dans le registre. 
   Pensez à appeler wrk.close() quand vous avez terminé !
*/

Support dans Firefox 1.0

Firefox 1.0 contient une interface bien plus simple pour accéder au registre Windows, sans la plupart des fonctionnalités des versions plus récentes. La fonctionnalité apparaît dans l'interface nsIWindowsShellService. Elle consiste en une seule méthode, getRegistryEntry(), et une série de constantes nommées de clefs racines. Vous pouvez l'utiliser comme dans cet exemple :

var wss = Components.classes["@mozilla.org/browser/shell-service;1"]
                    .getService(Components.interfaces.nsIWindowsShellService);
var id = wss.getRegistryEntry(wss.HKLM,
                              "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
                              "ProductId");
Note : Il n'existe aucune méthode pour définir une valeur de registre depuis cette interface.

Support dans SeaMonkey et autres applications non toolkit

Dans les vieilles version de SeaMonkey et autres applications non toolkit, il existe une interface appelée nsIWindowsRegistry contenant la même méthode et les mêmes constantes nommées comme celles décrites ci-dessus dans Firefox 1.0. Elles peuvent être utilisées comme ceci :

var wss = Components.classes["@mozilla.org/winhooks;1"]
                    .getService(Components.interfaces.nsIWindowsRegistry);
var id = wss.getRegistryEntry(wss.HKLM,
                              "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
                              "ProductId");

Compatibilité rétroactive

Si vous devez supporter Firefox 1.0 et des navigateurs plus anciens, vous devez vérifier quelles interfaces sont disponibles. Le canevas suivant vous permet de déterminer quelle interface utiliser :

if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
  // Firefox 1.5 ou suivant
}
else if ("@mozilla.org/winhooks;1" in Components.classes) {
  // SeaMonkey ou autre application non toolkit
}
else if ("@mozilla.org/browser/shell-service;1" in Components.classes) {
  var wss = Components.classes["@mozilla.org/browser/shell-service;1"]
                      .getService(Components.interfaces.nsIWindowsShellService);
  if ("getRegistryEntry" in wss) {
    // Firefox 1.0
  }
  else {
    // rien supporté
  }
}
else {
  // rien supporté
}

Étiquettes et contributeurs liés au document

Contributeurs ayant participé à cette page : Angevoyageur, Chbok, Mgjbot
Dernière mise à jour par : Angevoyageur,