IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Windows Management Instrumentation (WMI), seconde partie.

Cet article a pour objectif de mettre en pratique, sous Delphi, les aspects abordés dans l'article « Windows Management Instrumentation (WMI), première partie. ».

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Avant-propos

Testé avec Delphi 5 sous XP pro.
Version 1.0
Dernière mise à jour, le 26/06/2004

I-A. Le code sources des exemples

Vous trouverez ici une suite d'exemples en Delphi concernant la manipulation des objets de scripting WMI.J'ai fait en sorte d'ajouter le plus d'informations possible sur les méthodes et leurs paramètres.

Ce code vous permettra d'aborder simplement et progressivement WMI.

Merci d'utiliser le forum Delphi pour toute demande autre que les bugs et erreurs de documentation.

Sources des exemples.

II. Opérations de base

Il ne faut pas confondre les objets des API WMI (SwbemLocator, SwbemObject,SwbemServices…) et les classes d'objet ou les instances d'objet du référentiel WMI (Win32_Directory, Win32_Process…).

Les premiers de type TObject ou COM sont manipulables directement sous Delphi.

Exemple :

 
Sélectionnez
WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '','', wbemConnectFlagUseMaxWait, nil);

Les seconds ne sont pas manipulables directement sous Delphi.

L'exemple suivant n'est pas possible :

 
Sélectionnez
Var
  NewProcess: Win32_Process;

Begin
  NewProcess.Create('Notepad.exe','c:\temp',Nil, ProcessId);
End;

On doit utiliser un objet conteneur de type SwbemObject qui permettra de manipuler les propriétés et méthodes des classes d'objet et d'instances d'objet.

À noter que le VBScript permet une manipulation plus simple des propriétés et méthode des classes d'objet et d'instances d'objet.

II-A. Gérer les erreurs WMI

On utilise un objet TSWbemLastError qui nous informe sur les causes de l'erreur SI une erreur WMI est disponible.

Dans le cas contraire la méthode Connect permettant de se connecter à l'objet COM, déclenchera une exception.

 
Sélectionnez
begin
 Try
   WMILastError:=TSWbemLastError.Create(AOwner);
   WMILastError.ConnectKind := ckNewInstance;
   WMILastError.Connect;
   Result:=True;
 Except
 on E:EOleSysError do
  begin
     // Si aucune erreur existe le code d'erreur est égal à E_FAIL = $80004005
   Result:=False;
   FreeAndNil(WMILastError);
  end
 end;
end;

II-B. Comment contrôler les résultats ?

Je vous recommande dans les premiers temps d'utiliser en parallèle les outils WMI de Microsoft qui vous permettront de vérifier si votre code WMI renvoie les mêmes informations.

Cf. Windows Management Instrumentation (WMI), première partie.", chapitre Paramétrage WMI et outils divers.

III. Se connecter à WMI

Pour se connecter à WMI on utilise un composant TSWbemLocator.

La méthode ConnectServer établi une connexion au référentiel WMI dans un espace de nom particulier, dans l'exemple suivant on se connecte dans l'espace de nom ROOT\CIMV2.

La modification du curseur de la souris indique à l'utilisateur la phase de connexion au référentiel WMI. L'utilisation du flag wbemConnectFlagUseMaxWait évite une attente indéfinie en cas d'indisponibilité de la machine distante.

Si l'appel de la méthode ConnectServer réussi, elle renvoie un objet SwbemServices initialisé, sinon le traitement ne peut se poursuivre.

 
Sélectionnez
Var

  WMILocator:          TSWbemLocator;
  WmiService:          SWbemServices;

  OldCursor:           TCursor;

begin
 WMILocator:= TSWbemLocator.Create(self);
 try

  OldCursor := Screen.Cursor;
  Screen.Cursor := crSQLWait;

  WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '',
                                        '', wbemConnectFlagUseMaxWait, nil);

 Finally
  WMILocator.Free;
  Screen.Cursor:= OldCursor;
 end;
end;

IV. Récupérer une collection d'instances d'objet

Une fois un objet SWbemServices initialisé, on utilise sa méthode .InstancesOf.

Elle renvoie, dans un objet SwbemObjectSet, une collection d'instances de la classe spécifiée.

 
Sélectionnez
Var
  WmiService:          SWbemServices;
  wmiObjectSet:        SWbemObjectSet;

Begin
…
wmiObjectSet := wmiService.InstancesOf('Win32_OperatingSystem',
					wbemFlagReturnWhenComplete, 
					Nil);
…
end ;

V. Énumérer une collection WMI

Une fois une collection récupérée, on utilise une interface IEnumVariant qui implémente des fonctions d'énumération sur des données de type variant.

Elle nécessite le transtypage suivant sur un objet de type collection, ici WmiObjectSet :

 
Sélectionnez
ObjectEnumerator:= (WmiObjectSet._NewEnum) as IEnumVariant;

La méthode .Next permet une itération pour un ou plusieurs éléments. Elle renvoie S_OK tant qu'il reste des éléments à extraire.

L'élément récupéré de type OleVariant doit à son tour être transtypé pour permettre de le manipuler correctement :

 
Sélectionnez
WmiObject := IUnknown(ArrayVariant) as SWBemObject;

Ici l'objet ArrayVariant est transtypé vers la variable WmiObject de type SWBemObject.

On peut ensuite utiliser les propriétés et méthodes de la variable WmiObject .

Le transtypage de l'élément récupéré doit correspondre au type d'objet de la collection, par exemple pour une variable WmiProperty de type SWBemProperty :

 
Sélectionnez
WmiProperty:=IUnknown(ArrayVariant) as SWBemProperty;
Var
  WmiObject:           SWbemObject;
  wmiObjectSet:        SWbemObjectSet;

  ObjectEnumerator:    IEnumVariant;
  
 ArrayVariant:        OleVariant;   
 NumberItem:          LongWord;

Begin
 ….  
 // Affecte un énumérateur pour la collection d'objet SWbemObject
  ObjectEnumerator:= (WmiObjectSet._NewEnum) as IEnumVariant;

    // Retourne NumberItem éléments dans le tableau ArrayVariant,
    // ici 1 élément est demandé
  while (ObjectEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do
  begin
      // Récupére de la collection l'objet SWbemObject courant
   WmiObject := IUnknown(ArrayVariant) as SWBemObject;

      // Retrouve la propriétés de l'instance au format MOF
   Memo1.Lines.Add(AdjustLineBreaks(wmiObject.GetObjectText_(0)));
  end;

VI. Afficher le contenu d'un objet

La méthode .GetObjectText_ d'un objet SwbemObject renvoie presque toutes les informations d'un objet (classe ou instance).

Le texte reçu est au format MOF (Managed Object Format) et doit être reformaté en raison de fin de ligne incomplète (CR /LF).

 
Sélectionnez
Memo1.Lines.Add(AdjustLineBreaks(wmiObject.GetObjectText_(0)));

VI-A. Retrouver le path d'un objet

L'objet SWbemObjectPath permet de retrouver des informations sur un objet.

 
Sélectionnez
// Retrouve l'objet SWbemObjectPath contenant toutes les propriétés
WmiObjectPath:= WmiObject.Path_;
// retrouve le nom de la classe via le chemin d'accés relatif.
ClasseList.Add(WmiObjectPath.RelPath);

VII. Récupérer une instance ou une définition de classe

Une fois un objet SWbemServices initialisé, on utilise sa méthode .Get.

Elle renvoie, dans un objet SwbemObject, une instance ou une définition de classe si le paramètre strObjectPath contient respectivement un chemin d'objet d'instance ou un chemin d'objet de classe.

Chemin d'objet d'instance

 
Sélectionnez
WmiObject:= Service.Get(' Win32_Directory.Name="c:\windows\system32\wbem", 0, nil);

La propriété Name étant ici la clé de l'instance.

Chemin d'objet de classe

 
Sélectionnez
WmiObject:=WmiService.Get('Win32_ Directory ',0,Nil);

VIII. Récupérer une collection de propriétés

La propriété Properties_ de l'objet SWbemObject renvoie une collection de type SwbemPropertySet contenant toutes les propriétés de la classe ou de l'instance d'objet.

 
Sélectionnez
Var
  ListePropriétés : SwbemPropertySet ;
  WmiObjet :        SWbemObject ;

Begin
  ListePropriétés := WmiObjet.Properties_;

IX. Récupérer une collection de qualificateurs

La propriété Qualifiers_ de l'objet SWbemObject renvoie une collection de type SwbemQualifiersSet contenant toutes les propriétés de la classe ou de l'instance d'objet.

 
Sélectionnez
Var
  ListeQualificateurs : SwbemQualifiersSet ;
  WmiObjet :              SWbemObject ;

Begin
  ListeQualificateurs := WmiObjet.Qualifiers_;

X. Récupérer une collection de méthodes

La propriété Methods_ de l'objet SWbemObject renvoie une collection de type SwbemMethodsSet contenant toutes les propriétés de la classe ou de l'instance d'objet.

 
Sélectionnez
Var
  ListeMethodes : SwbemMethodsSet ;
  WmiObjet :        SWbemObject ;

Begin
  ListeMethods := WmiObjet.Methods_;

XI. Récupérer un élément d'une collection en utilisant son nom

La méthode .Item d'un objet collection permet d'extraire un élément par son nom.

 
Sélectionnez
WmiProperty:= Instance.Properties_.Item('CommandLine',0);

XII. Afficher une propriété

Un objet SWBemProperty représente une propriété de classe. Cet objet possède la propriété Name qui contient le nom de la propriété manipulée.

Avant de récupérer sa valeur par la méthode .Get_Value, on doit lire la propriété CIMType qui détermine le type de donnée de la propriété manipulée puis la convertir vers une chaîne de caractères.

Ici la propriété de nom Description est de type string (wbemCimtypeString), on peut donc directement l'insérer dans un TMemo.

 
Sélectionnez
...
 If WmiProperty.name='Description' then
    if WmiProperty.CIMType=wbemCimtypeString then
      Memo1.Lines.Add(WmiProperty.Get_Value);
    else Convertion
 ...

XII-A. Gestion des différents types de donnée

Voici une fonction de conversion prenant en charge tous les types de donnée possible pour la propriété CIMType.

 
Sélectionnez
Function WMIPropertyToStr(WmiService:SWbemServices; WmiProperty : SWbemProperty):String;
var sValue: String;
    Count:  Integer;
    Value: Variant;
    WmiObjet : SWbemObject;

begin
 try
    Value:=WmiProperty.Get_Value;
    sValue := '';
    if VarIsNull(Value) then
      sValue := 'Is Null'
    else
     try
      case WmiProperty.CIMType of
        wbemCimtypeSint8,
        wbemCimtypeUint8,
        wbemCimtypeSint16,
        wbemCimtypeUint16,
        wbemCimtypeSint32,
        wbemCimtypeUint32,
        wbemCimtypeSint64,
        wbemCimtypeUint64:
          if VarIsArray(Value) then begin
            if VarArrayHighBound(Value, 1) > 0 then
              for Count := 1 to VarArrayHighBound(Value, 1) do
                sValue := sValue + ' ' + IntToStr(Value[Count]);
          end
          else
            sValue := IntToStr(Value);

        wbemCimtypeReal32,
        wbemCimtypeReal64:
          sValue := FloatToStr(Value);

        wbemCimtypeBoolean:
          if Value then sValue := 'True' else sValue := 'False';

          // Single 16-bit Unicode character in Universal Character Set-2 (UCS-2) format
        wbemCimtypeChar16,
         // Unicode character string
        wbemCimtypeString:
          if VarIsArray(Value) then begin
            if VarArrayHighBound(Value, 1) > 0 then
              try
              for Count := 1 to VarArrayHighBound(Value, 1) do
                sValue := sValue + ' ' + Value[Count];
              except
               on E: EConvertError do
                 ShowMessage(E.Message);
              end;
          end
          else
            sValue := Value;

        wbemCimtypeDatetime:
          sValue := Value;

         // Référence d'objet, le chemin de l'objet peut être
         //	un nom complet serveur\espace de nom
         //	ou relatif dans le même espace de nom
        wbemCimtypeReference: begin
                                // Récupére l'objet référençé
                               WmiObjet:=WmiService.Get(Value,wbemFlagReturnWhenComplete,Nil);
                               sValue:=AdjustLineBreaks(WmiObjet.GetObjectText_(0))
                              end;
          // Objet imbriqué
          // Renvoie le path de la propriété de type Objet
        wbemCimtypeObject: begin
                               // Récupére l'objet imbriqué
                             WmiObjet:=IUnknown(WmiProperty.Get_Value) as SWbemObject ;
                             sValue:=WmiObjet.Path_.Relpath;
                           end;
      end; // case
     except
      on E: EVariantError do
       ShowMessage('WMIPropertyToStr : Erreur de convertion de variant');
     end;
 Finally
  Result:=sValue;
 end;
end;

XIII. Modifier une propriété

La méthode .Set_Value permet de modifier le contenue d'une propriété.

Dans l'exemple suivant on modifie la propriété CommandLine de la méthode .Create de la classe Win32_Process.

 
Sélectionnez
Var
  PropertyCommandLine: OleVariant;
  Instance_inParameters:   SWbemObject;

Begin
   WmiProperty:= Instance_inParameters.Properties_.Item('CommandLine',0);
   PropertyCommandLine:= 'Notepad.exe';
   WmiProperty.Set_Value(PropertyCommandLine);

Dans l'unité Delphi la déclaration de la propriété Value de l'objet SWBemProperty n'existe pas, utilisez la méthode .Set_Value.

XIV. Mettre à jour un objet dans le référentiel WMI

Une fois un objet modifié, exécutez sa méthode .Put_ afin de le modifier dans le référentiel WMI.

 
Sélectionnez
Var
  WmiObject:           SWbemObject;

  PropertyMaxFileSize: SWbemProperty;

  MaxFileSize :  OleVariant;

Begin
    // Retrouve la propriété à modifier
     PropertyMaxFileSize:= WmiObject.Properties_.Item('MaxFileSize',0);

        // Nouvelle valeur de la propriété
     MaxFileSize:= 512000; // 512 Ko (unité byte)

       //Renseigne la valeur de la propriété
     PropertyMaxFileSize.Set_Value(MaxFileSize);

       // Mise à jour de l'instance courante
     WmiObject.Put_(wbemFlagReturnWhenComplete,Nil) ;

XV. Exécuter une requête WQL

La méthode .ExecQuery de l'objet SwbemServices permet d'interroger le référentiel en exécutant une requête WQL synchrone.

Cette méthode renvoie une collection de type SwbemObjectSet contenant des objets correspondants à la requête.

Le premier paramètre peut être une variable chaîne de caractère.

 
Sélectionnez
var
  WmiService:          SWbemServices;

  WmiObject:           SWbemObject;
  wmiObjectSet:        SWbemObjectSet;

  ObjectEnumerator:    IEnumVariant;
  ArrayVariant:        OleVariant;  // Tableau de variant
  NumberItem:          LongWord;

begin
 …
    WmiObjectSet := wmiService.ExecQuery('SELECT Name FROM Win32_Service Where
 					State=''Stopped''',
					'WQL',
					wbemFlagReturnImmediately, nil);

XVI. Modifier les privilèges de sécurité

La propriété Security_ d'un objet SWbemServices contient la collection Privileges contenant des objets de type SWbemPrivilege permet de modifier les priviléges de sécurité.

Dans l'exemple suivant on ajoute le privilège 'Shutdown' avant d'exécuter la méthode Win32Shutdown de la classe Win32_OperatingSystem.

 
Sélectionnez
WmiServices.Security_.Privileges.Add(wbemPrivilegeShutdown, True);

XVII. Exécuter une méthode

La méthode ExecMethod_ d'un objet SWbemObject permet d'exécuter une méthode de classe ou d'instance. Cette méthode renvoie un objet qui contient la valeur de retour et les paramètres modifiés.

Mais son exécution nécessite quelques traitements préliminaires.

Retrouver la définition, de la classe ou de l'instance concernée, par le méthode .Get.

Modifier si besoin les privilèges de sécurité nécessaires à l'appel de méthode.

Récupérer, à partir de la collection Methods_ , les propriétés de la méthode que vous souhaitez exécuter. Pour ce faire vous pouvez utiliser la méthode .Item.

Créer une nouvelle instance de la méthode de la classe concernée en utilisant la méthode .SpawnInstance_ . Cette création alloue l'espace mémoire pour manipuler les paramètres de cette méthode. La collection InParameters.properties_ contient le nombre, le nom et le type des paramètres de cette nouvelle instance de méthode.

Renseigner les paramètres de la méthode avec les valeurs appropriées.

Appeler la méthode .ExecMethod_.

Et enfin si vous souhaitez contrôler les valeurs de retour de la méthode consulter les propriétés de l'objet renvoyé par l‘exécution de la méthode .ExecMethod_.

 
Sélectionnez
var
  WMILocator:            TSWbemLocator;

  Process,
  NewProcess,
  Instance_inParameters: SWbemObject;

  WmiProperty:           SWbemProperty;

  ProcessMethod:         ISWbemMethod;

  PropertyCommandLine,
  PropertyReturnValue,
  ProcessID		 OleVariant;


begin
  WMILocator:= TSWbemLocator.Create(self);

 try
    // Création d'une connexion à un espace de nom local
    // ici le nom de l'espace de nom cible est : CIMV2
    // L'appel renvoie un pointeur sur un objet SWbemServices
   WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '',
                                         '', wbemConnectFlagUseMaxWait, nil);


    // Retrouve la définition de la classe Win32_Process
     // Sur le site de MS, la classe Win32_Process se trouve dans :
     //   Win32 Classes.Operating system Classes.Process
   Process:=WmiService.Get('Win32_Process',0,Nil);

    // Si vous devez modifier la sécurité nécessaire à l'appel de méthode,
    // par exemple 'Shutdown' utilisez :
    //     wmiServices.Security_.Privileges.Add(wbemPrivilegeShutdown, True);

    // Récupère, à partir de la collection de méthode,
    // la définition de la méthode 'Create' de la classe Win32_Process
    // qui correspond à ceci :
          {    Win32_Process.Create(IN CommandLine string ,
                                    IN CurrentDirectory   string ,
                                    IN ProcessStartupInformation Win32_ProcessStartup ,
                                    OUT ProcessId uint32)
              Valeur de retour :
                  [Out] ProcessId uint32 ;
                  [out] ReturnValue uint32 ;
          }


   ProcessMethod:=Process.Methods_.Item('Create', 0);

    // Crée une nouvelle instance de la méthode '.Create' de la classe Win32_Process
    // alloue l'espace mémoire pour manipuler ces paramètres.
    // ProcessMethod.InParameters.Properties_ contient la liste des paramètres de la méthode
   Instance_inParameters:= ProcessMethod.InParameters.SpawnInstance_(0);

    // Retrouve la propriété 'CommandLine' de la méthode '.Create'
   WmiProperty:= Instance_inParameters.Properties_.Item('CommandLine',0);

     // Nom du programe à exécuter
   PropertyCommandLine:= 'Notepad.exe';

    //Renseigne la valeur de la propriété 'CommandLine' de la méthode '.Create'
   WmiProperty.Set_Value(PropertyCommandLine);

    //Crée un process Via la Méthode '.Create'
   NewProcess:= Process.ExecMethod_('Create', Instance_inParameters, wbemFlagReturnWhenComplete, nil);

   { Un objet OutParameters est créé par la méthode exécutée }

    // Récupère la valeur de retour de la méthode via la propriété 'ReturnValue'
   PropertyReturnValue:= NewProcess.Properties_.Item('ReturnValue', 0);

   if PropertyReturnValue.Value = 0 then
     begin
       // Réutilise la propriété pour récupérer l'ID de process
      PropertyReturnValue:= NewProcess.Properties_.Item('ProcessId', 0);
      ProcessID:=PropertyReturnValue.Value;
      MessageBox(0, PChar('Process crée.'+#10#13+'Pid : '+inttostr(ProcessID)),
                 PChar(Form1.Caption), MB_OK);
     end
    else
     MessageBox(0, PChar('Erreur '+inttostr(PropertyReturnValue.Value)+' lors de la création du process.'),
                PChar(Form1.Caption), MB_OK);
 Finally
  WMILocator.Free;
 end;

XVIII. Exécuter une requête d'événement WQL synchrone

La méthode .ExecNotificationQuery de l'objet SwbemServices permet d'interroger le référentiel périodiquement (polling) en exécutant une requête WQL d'événement synchrone.

Le polling de l'événement se fait dans l'intermédiaire de WMI et non par un provider.

Cette méthode renvoie un objet de type SwbemEventSource.

La notification d'événement se faisant via l'appel de sa méthode .NextEvent.

L‘intervalle de polling recommandé est de 300 secondes pour éviter de monopoliser les ressources de la machine.

Dans cet exemple on souhaite récupérer les événements de suppression d'instance de process en utilisant la classe d'événement __instancedeletionevent sur la propriété TargetInstance de classe Win32_Process.

Seuls les événements concernant les instances de process en cours ayant changées pendant l'intervalle de polling seront détectés.

Si après l'exécution de la requête et pendant l'intervalle de polling de 300 secondes, vous exécutiez une application puis la supprimiez tout de suite après, un événement __instancedeletionevent est déclenché dans le référentiel WMI.

Mais cet événement ne sera pas 'vue' par la requête, car le contexte (nombre de process) ne présentera aucun changement entre le moment où la requête est exécutée par la méthode .ExecNotificationQuery et le moment où l'intervalle de polling se déclenche afin de contrôler si un événement attendu c'est produit.

Il n'a donc pas, avec ce type de requête, d'historique des événements déclenchés pendant la durée du polling.

Le premier paramètre peut être une variable chaîne de caractères.

 
Sélectionnez
Var
  WmiMonitoredProcesses:  	SWbemEventSource;

  WmiLatestProcess,
  WmiObjet:            		SWbemObject;

  Query : 			String;
Begin

   // Recherche les événements de type '__instancedeletionevent' (Intrinsèque).
   // WMI effectue le polling toute les 1 secondes.
   // Seule les instances de la classe Win32_Process sont concernées.
  Query:='Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"';
  WmiMonitoredProcesses:=WMIService.ExecNotificationQuery(Query,
                                                          'WQL',
                                                          wbemFlagForwardOnly +
                                                          wbemFlagReturnImmediately,
                                                          Nil);

XIX. Récupérer une notification d'événement synchrone

La notification d'événement se fait par l'appel de la méthode .NextEvent d'un objet de type SwbemEventSource.

Cette méthode est bloquante car elle attend un événement avant de se terminer.

Si un événement est disponible elle le retrouve et renvoie un objet SWbemObject contenant une instance de la classe d'événement demandé par la requête associée.

 
Sélectionnez
Var
  WmiMonitoredProcesses:  	SWbemEventSource;

  WmiLatestProcess,
  WmiObjet:            		SWbemObject;

  Query : 			String;

Begin 
  Query:='Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"';
  WmiMonitoredProcesses:=WMIService.ExecNotificationQuery(Query,
                                                          'WQL',
                                                          wbemFlagForwardOnly +
                                                          wbemFlagReturnImmediately,
                                                          Nil);

   // Renvoie une classe de type '__InstanceDeletionEvent'
   // -1 = Attente indéfinie. Le traitement attend un événement...
  WmiLatestProcess:= WmiMonitoredProcesses.NextEvent(-1);

   // Retrouve l'objet contenue dans la propriété TargetInstance
   // à partir de l'objet crée par la méthode WmiMonitoredProcesses.NextEvent
   // L'objet retrouvé contient une copie de l'instance du process supprimé.
  WmiObjet:=IUnknown(WmiLatestProcess.Properties_.Item('TargetInstance',0).Get_Value) as SWbemObject;

XX. Exécuter une requête d'événement WQL asynchrone

Ajouter un composant TSWbemSink sur votre fiche. Renseignez ces gestionnaires d'événements :

OnCompleted est déclenché quand une opération asynchrone est terminée, l'appel de la méthode TSWbemSink.Cancel déclenche cet événement.

OnObjectPut est déclenché après une opération PUT asynchrone, ie. aprés mise à jour d'un instance ou d'une classe.

OnProgress est déclenché pour fournir le statut d'une opération asynchrone. Attention, cet événement n'est pas pris en charge par tous les providers.

OnObjectReady est déclenché quand un objet, fourni par un appel asynchrone est disponible. C'est cet événement qui sera le plus utilisé.

La méthode .ExecNotificationQueryAsync de l'objet SwbemServices permet d'interroger le référentiel périodiquement (polling) en exécutant une requête WQL d'événement asynchrone.

Elle similaire à la méthode .ExecNotificationQuery en dehors du fait que l'on doit spécifier un Object collecteur qui reçoit de WMI les notifications d'événements asynchrone et les renvoie vers le client.

À noter que le collecteur peut gérer les événements de plusieurs requêtes asynchrones.

Le code suivant exécute la requête de polling et déclenche la collecte des événements effectué par le composant TSWbemSink.

Vous devez renseigner le paramètre iFlags de l'appel asynchrone avec la valeur wbemFlagSendStatus si vous voulez recevoir des mises à jour de statut, autrement cet événement n'est pas déclenché. Sous réserve que le provider gère les événements de mises à jour de statut.

 
Sélectionnez
var
  Query:               String;

begin
  Query:='Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"';

  WMIService.ExecNotificationQueryAsync(SWbemSink1.DefaultInterface,
                                        Query,
                                        'WQL',
                                        wbemFlagSendStatus,
                                        Nil, Nil);
end;

XXI. Récupérer une notification d'événement asynchrone

La notification d'événement se fait via le gestionnaire d'événements TSWbemSink.OnObjectReady d'un objet de type TSWbemSink.

Dés qu'un objet est disponible WMI déclenche cet événement et renvoie un objet contenant une instance de la classe demandé par la requête associée.

Dans l'exemple suivant le code est lié à la requête suivante :

 
Sélectionnez
Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"

L'objet reçu, objWbemObject, est une instance de la classe '__InstanceDeletionEvent'.

On doit donc transtyper sa propriété TargetInstance pour récupérer la copie de l'instance du process supprimé.

 
Sélectionnez
procedure TForm1.SWbemSink1ObjectReady(Sender: TObject; var objWbemObject,
  objWbemAsyncContext: OleVariant);
// Déclenché lorsqu'un objet fourni par l'appel asynchrone est disponible.
// ObjWbemObject contient l'objet retourné

var WmiObjet: ISWbemObject;

begin
     // L'objet retourné contient une copie de l'instance du process supprimé.
  WmiObjet:=IUnknown(objWbemObject.Properties_.Item('TargetInstance',0).Value) as ISWbemObject;

  Memo1.Lines.Add(#13#10+'Le process '+WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value)+
                  ' s''est terminé.'+#13#10);
  Memo1.Lines.Add(WmiObjet.Path_.path);
  Memo1.Lines.Add(AdjustLineBreaks(WmiObjet.GetObjectText_(0)));
end;

XXII. Où trouver des informations sur les classes WMI disponibles ?

Liste et définitions des classes WMI.

Par exemple vous trouverez des informations sur Windows dans une des catégories de base nommée Win32 Classes qui contient les sous-catégories suivantes :

  • Computer system hardware
  • Operating system Classes
  • Installed applications
  • WMI service management
  • Performance counters

XXIII. Windows Management Instrumentation (WMI), première partie.

Article précédent : Les bases de WMI.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2004 Laurent Dardenne. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.