FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 123, nombre de questions : 923, dernière mise à jour : 29 avril 2020  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

Commentez


SommaireSystèmeWMIProvider (7)
précédent sommaire suivant
 

WMI propose des données sur des objets managés par Windows au travers de providers. Un provider (fournisseur de données) est un objet COM qui agit en tant qu'intermédiaire entre WMI et un objet géré.

Au travers de WMI, une application peut demander et envoyer des informations vers l'objet géré.
Un provider retrouve les données d'un composant système, tel qu'un process ou SNMP ou encore IIS et renvoie ces informations de WMI vers une application cliente.

Exemples :

  • quand une application ou un script demande des informations sur un processus en utilisant la classe WMI Win32_Process, les données sont obtenues dynamiquement via le provider pré-installé.
  • une application peut modifier et rechercher des informations de la base de registres via WMI par l'intermédiaire du provider nommé System Registry Provider.

Il existe plusieurs types de provider :
  • Provider d'instance
    cf. classe __InstanceProviderRegistration
  • Provider de classe
    cf. classe __ClassProviderRegistration
  • Provider de méthode
    cf. classe __MethodProviderRegistration
  • Provider de propriété
    cf. classe __PropertyProviderRegistration
  • Provider d'événement
    cf. classe __EventProviderRegistration
  • Provider d'événement client
    cf. classe __EventConsumerProviderRegistration

Par exemple le fichier C:\WINDOWS\system32\wbem\msiprov.dll héberge le provider pour MSI.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Les événements de WMI sont des occurrences qui correspondent aux situations qui surviennent soit dans le monde réel, soit lors de changements dans le référentiel CIM géré par le manager d'objet CIM (CIMOM, Common Information Model Object Manager).

Après un événement, une notification le concernant est générée soit par un provider d'événement, soit par le manager d'objet CIM lui-même. Les notifications sont fournies par le manager d'objet CIM à un ou plusieurs destinataires enregistrés connus comme clients d'événements.

  • Les providers d'événement envoient des notifications en réponse aux occurrences d'événement, que des clients soient ou non enregistrés.
  • Les clients d'événement s'enregistrent pour recevoir des notifications sans savoir comment et par qui les événements et leurs notifications correspondantes sont fournis.
    Les clients s'enregistrent pour recevoir des notifications en indiquant un filtre, créé en utilisant le langage d'interrogation WQL de WMI. La requête décrit les conditions dans lesquelles le client est configuré pour recevoir une notification.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

L'objet TSWbemSink (collecteur) est implémenté par des applications clientes pour recevoir les résultats des opérations asynchrones et des notifications d'événements.

Pour effectuer un appel asynchrone, vous devez créer une instance d'un objet TSWbemSink et le passer en paramètre, souvent nommé ObjWbemSink, aux méthodes nécessitant ce type d'objet.

Par exemple SWbemServices.ExecNotificationQueryAsync.

Les évènements dans votre implémentation de TSWbemSink sont déclenchés quand le statut ou les résultats sont retournés ou que l'appel est terminé.

Les gestionnaires d'évènements Delphi sont :

  • OnCompleted est déclenché quand une opération asynchrone est terminée.
  • OnObjectPut est déclenché après une opération PUT asynchrone.
  • OnObjectReady est déclenché quand un objet résultant d'un appel asynchrone est disponible.
  • OnProgress est déclenché pour fournir le statut d'une opération asynchrone.

Si les événements sont produits à partir d'un provider qui implémente les mises à jour de statut, vous pouvez gérer l'événement OnProgress pour informer les utilisateurs à propos d'un changement de statut lors d'une opération asynchrone.

La méthode Cancel annule toutes les opérations asynchrones liées à l'instance.

L'exemple suivant initialise un client d'évènement temporaire asynchrone recherchant les fins de processus.
La variable
Code delphi : Sélectionner tout
WMILocator: TSWbemLocator;
est déclarée dans la partie public de la fiche et la variable CollecteurEvenement est un composant TSWbemSink placé sur la fiche.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure TForm1.BtConnexionClick(Sender: TObject); 
var 
  WmiService:          SWbemServices; 
  WmiObjet:            SWbemObject; 
  Query:               String; 
  
begin 
WMILocator:= TSWbemLocator.Create(self); 
  
WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                        '', wbemConnectFlagUseMaxWait, nil); 
  
     // Recherche les événements de type  
     // '__instancedeletionevent' ( Intrinsèque ) 
   Query:='Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"'; 
  
     // On passe à cette méthode l'Object collecteur qui reçoit  
     // les notifications d'événements asynchrones. 
  WMIService.ExecNotificationQueryAsync(CollecteurEvenement.DefaultInterface, 
                                        Query, 
                                        'WQL', 
                                        wbemFlagSendStatus, 
                                        Nil, Nil);
L'accès à la propriété DefaultInterface crée, s'il est à NIL, un objet récepteur d'événements (ISWbemSink) puis le connecte au collecteur d'événements (TSWbemSink dérivé de TOLEServer).
Vous pouvez consulter ce tutoriel pour de plus amples informations sur les gestion des événements d'un objet COM.

Avant de supprimer l'objet ISWbemSink on doit appeler la méthode CollecteurEvenement.Cancel. Cet appel déclenche l'événement OnCompleted.
La propriété DefaultInterface étant une interface sa libération est donc automatique.
L'appel implicite de la méthode Disconnect n'est pas nécessaire car il est effectué automatiquement lors de libération de l'interface.
Code delphi : Sélectionner tout
1
2
3
4
5
6
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  // libère les ressources WMI 
 CollecteurEvenement.Cancel 
 WMILocator.Free; 
end;
Le gestionnaire d'événement Delphi pour la méthode Cancel étant :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
procedure TForm1.btCancelSinkClick(Sender: TObject); 
Var WMILastError: TSWbemLastError; 
begin 
 CollecteurEvenement.Cancel; 
  
 if ExistWmiErreur(WMILastError,Self) 
  then 
    begin 
     ShowWMIErreur('Erreur dans la méthode Cancel du collecteur.',WMILastError,Nil); 
     // appel de WMILastError.Release automatique par Delphi 
    end; 
end;
Il n'est pas nécessaire d'appeler CollecteurEvenement.Disconnect car le récepteur d'événements existe toujours, si on relance une requête via la methode ExecNotificationQueryAsync, le collecteur reçoit de nouveau les événements WMI.

Note:
Un seul objet de ce type peut être utilisé pour collecter les informations de plusieurs requêtes d'événements asynchrones.

Voici le code associé aux procédures d'événements de l'objet nommé CollecteurEvenement :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
procedure TForm1.CollecteurEvenementCompleted(Sender: TObject; 
  iHResult: TOleEnum; const objWbemErrorObject: ISWbemObject; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
//Déclenché lorsqu'une opération asynchrone est terminée. 
var S:String; 
begin 
  // Consultez le SDK pour le détail des codes d'erreurs 
  Memo1.Lines.Add('Opération asynchrone terminée.'); 
  If iHResult<> WBEM_S_NO_ERROR 
   then //ShowWMIErreur('Collecteur événement Completed',objWbemErrorObject,nil ); 
    begin 
     S:='Informations d''erreur WMI :'+#13#10+#13#10+ 
        'Collecteur événement Completed'+#13#10+ 
        'Operation : '+objWbemErrorObject.Properties_.Item('Operation',0).Get_Value+#13#10+ 
        'Provider : '+objWbemErrorObject.Properties_.Item('ProviderName',0).Get_Value+#13#10+ 
        'Description : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('Description',0).Get_Value)+#13#10+ 
        'parametre : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('ParameterInfo',0).Get_Value)+#13#10+ 
        'Code : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('StatusCode',0).Get_Value); 
     ShowMessage(S); 
   end; 
end; 
  
procedure TForm1.CollecteurEvenementObjectPut(Sender: TObject; 
  const objWbemObjectPath: ISWbemObjectPath; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
  //Déclenché aprés une opération PUT asynchrone. 
begin 
 Memo1.Lines.Add('Opération Put .'); 
end; 
  
  
procedure TForm1.CollecteurEvenementObjectReady(Sender: TObject; 
  const objWbemObject: ISWbemObject; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
//Déclenché lorsqu'un objet fourni par l'appel asynchrone est disponible. 
// objWbemObject contient l'objet retourné 
var WmiObjet: SWbemObject; 
begin 
   // Retrouve l'objet contenu dans la propriété TargetInstance 
   // qui contient une copie de l'instance du process supprimé. 
  WmiObjet:=IUnknown(objWbemObject.Properties_.Item('TargetInstance',0).Get_Value) as SWbemObject; 
  Memo1.Lines.Add('Le process '+WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value)+ 
                  ' est terminé.'+#13#10); 
  Memo1.Lines.Add(WmiObjet.Path_.path); 
  Memo1.Lines.Add(AdjustLineBreaks(WmiObjet.GetObjectText_(0))); 
end; 
  
  
procedure TForm1.CollecteurEvenementProgress(Sender: TObject; 
  iUpperBound, iCurrent: Integer; const strMessage: WideString; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
  //Déclenché pour fournir l'état de l'opération asynchrone. 
// Dépend du provider: tous ne semblent pas gérer cet événement. 
begin 
 // Consultez le SDK pour le détail des paramètres 
Memo1.Lines.Add('Evénement on Progress'); 
 Memo1.Lines.Add(IntToStr(iCurrent)+'/'+IntToStr(iUpperBound)+' Objet. '+#13#10+strMessage); 
end;

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Lien MSDN : SWbemSink

WMI contient une infrastructure d'évènements qui génère des notifications lors de changements de données et de services de WMI.
Par exemple, si une application crée un nouvel objet dans le référentiel CIM de WMI, WMI génère un évènement nommé __InstanceCreationEvent.

Vous pouvez créer une requête semi-synchrone ou asynchrone pour surveiller les changements dans l' Event logs, la création de processus, le statut d'un service, la disponibilité d'un ordinateur ou l'espace libre d'un disque, etc.

La notification d'un changement sur les données standards de WMI s'appelle un événement intrinsèque .
Par exemple les évènements __InstanceCreationEvent ou __NamespaceDeletionEvent sont des événements intrinsèques.

La notification d'un changement qu'un provider fait pour définir un évènement le concernant s'appelle un évènement extrinsèque.
Par exemple, les providers System Registry, Power Management Event, et Win32 définissent leurs propres événements.

Typiquement, une classe qui définit un événement a un nom se terminant par le mot Event. Par exemple, le provider Win32 a la classe Win32_NTLogEvent. Quand un provider possède une classe d'événement, vous effectuez une requête pour un événement intrinsèque.
On utilise la méthode SWbemServices.ExecNotificationQuery pour exécuter une requête d'évènement synchrone.

Dans notre exemple nous souhaitons être informés lors d'une suppression d'un process quelconque. La requête WQL se décompose de la maniére suivante :

Code delphi : Sélectionner tout
1
2
//Recherche la suppression d'instance 
Query:='Select * from __instancedeletionevent within 1 where TargetInstance isa "Win32_Process"';
  • __instancedeletionevent est une classe représentant un évènement de suppression d'une instance dans le référentiel WMI,
  • within 1 indique à WMI d'effectuer un contrôle toutes les 1 secondes,
  • TargetInstance est une propriété de type objet de la classe __instancedeletionevent, elle contient l'instance concernée par notre requête,
  • isa est un opérateur signifiant à WMI de renvoyer toutes les sous-classes de la classe spécifiée, Microsoft recommande un délai de pooling de 300 secondes afin d'éviter les surchages processeur.

Si après le démarrage du pooling, une application est exécutée puis tout de suite supprimée, pendant ce laps de temps l'événement n'est pas 'vu' par WMI. La requête s'effectue sur les process existants au moment de son exécution.

Pour récupérer l'événement on utilise l'objet SWbemEventSource et plus particulièrement sa méthode NextEvent qui attend et renvoie le premier événement disponible du type attendu.
Cette approche bloque donc le déroulement du programme client.
Voici l'exemple complet :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
procedure TForm1.BTConnexionClick(Sender: TObject); 
//Client d'évènement temporaire recherchant les fins de processus. 
  
var 
  WMILocator:          TSWbemLocator; 
  WmiService:          SWbemServices; 
  
  WmiMonitoredProcesses:  SWbemEventSource; 
  
  WmiLatestProcess, 
  WmiObjet:            SWbemObject; 
  OldCursor:           TCursor; 
  Query:               String; 
  
begin 
 WMILocator:= TSWbemLocator.Create(self); 
 try 
  OldCursor := Screen.Cursor; 
  Screen.Cursor := crSQLWait; 
  WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                        '', wbemConnectFlagUseMaxWait, nil); 
  
  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éé 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; 
  
  Memo1.Lines.Add('Le process '+WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value)+ 
                  ' est terminé.'+#13#10); 
  Memo1.Lines.Add(WmiObjet.Path_.path); 
  Memo1.Lines.Add(AdjustLineBreaks(WmiObjet.GetObjectText_(0))); 
  
 Finally 
  WMILocator.Free; 
  Screen.Cursor:= OldCursor; 
 end; 
end;
Ici c'est WMI qui recherche l'événement au lieu d'un provider (objet COM) dans le cas d'un client permanent.

En utilisant l'outil FileMon de sysinternals on peut voir les nombreuses lectures sur le référentiel 'C:\WINDOWS\system32\wbem\Repository\FS\INDEX.BTR' effectuées par le process "C:\WINDOWS\System32\svchost.exe -k netsvcs" qui référence le service WinMgmt :%SystemRoot%\system32\wbem\WMIsvc.dll.

Ces lectures se font uniquement lors de la suppression d'un process et pas toutes les secondes comme on pourrait le supposer.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Une fois configuré un objet de type TSWbemSink il reste à créer au minimum les gestionnaires d'événements onReady et onCompleted, les 2 autres sont d'un usage moins courant.

Pour onReady on reçoit les paramètres suivants :

  • objWbemObject contient l'objet retourné
  • objWbemAsyncContext permet de différencier l'événement reçu dans le cas où l'on utilise plusieurs requêtes d'evénements avec un même collecteur de données.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
procedure TForm1.CollecteurEvenementObjectReady(Sender: TObject; 
  const objWbemObject: ISWbemObject; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
//Déclenché lorsqu'un objet fourni par l'appel asynchrone est disponible. 
  
var WmiObjet: SWbemObject; 
  
begin 
   // L'objet retrouvé contient une copie de l'instance du process supprimé. 
  WmiObjet:=IUnknown(objWbemObject.Properties_.Item('TargetInstance',0).Get_Value) as SWbemObject; 
  Memo1.Lines.Add('Le process '+WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value)+ 
                  ' est terminé.'+#13#10); 
  Memo1.Lines.Add(WmiObjet.Path_.path); 
  Memo1.Lines.Add(AdjustLineBreaks(WmiObjet.GetObjectText_(0))); 
end;
Pour onCompleted on reçoit les paramètres suivants :
  • iHResult : Indique si l'appel asynchrone à réussi Dans ce cas, il contient la valeur WBEM_S_NO_ERROR (0) sinon il contient code d'erreur.
  • objWbemErrorObject : Contient, en cas d'erreur, un objet SWbemLastError.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
procedure TForm1.CollecteurEvenementCompleted(Sender: TObject; 
  iHResult: TOleEnum; const objWbemErrorObject: ISWbemObject; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
//Déclenché lorsqu'une opération asynchrone est terminé. 
  
var S:String; 
  
begin 
  Memo1.Lines.Add('Opération asynchrone terminée.'); 
  If iHResult<> WBEM_S_NO_ERROR 
   then 
      // Appel asynchrone annulé. 
      // Ce n'est pas une erreur, l'appel de TSWbemSink.Cancel provoque 
      // l'appel de cet événement 
    if iHResult= wbemErrCallCancelled 
     then exit 
     else 
      begin 
       S:='Informations d''erreur WMI :'+#13#10+#13#10+ 
          'Collecteur événement Completed'+#13#10+ 
          'Operation : '+objWbemErrorObject.Properties_.Item('Operation',0).Get_Value+#13#10+ 
          'Provider : '+objWbemErrorObject.Properties_.Item('ProviderName',0).Get_Value+#13#10+ 
          'Description : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('Description',0).Get_Value)+#13#10+ 
          'parametre : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('ParameterInfo',0).Get_Value)+#13#10+ 
          'Code : '+WMIVariantToStr(objWbemErrorObject.Properties_.Item('StatusCode',0).Get_Value); 
      ShowMessage(S); 
    end; 
end;
Les erreurs possibles sont :
  • wbemErrFailed : Erreur non spécifié.
  • wbemErrOutOfMemory : pas assez de mémoire pour effectuer l'opération.
  • wbemErrTransportFailure : Une erreur réseau s'est produite, empêchant le déroulement normal de l'opération.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Dans ce cas, on doit utiliser une collection de valeurs nommées du type TSWbemNamedValue et un collecteur de données.

Ajoutons deux variable dans la partie Public de la fiche :

Code delphi : Sélectionner tout
1
2
ProcessContext : TSWbemNamedValueSet; 
  EventLogContext :TSWbemNamedValueSet;
Dans notre exemple nous souhaitons surveiller les événements 'fin de process' et 'ajout au journal des eventlog'.

Une valeur nommée, une simple chaîne de caractères, nous permettra de différencier, dans la méthode TSWbemSink.OnReady, les évènements que nous souhaitons gérer.
Créons d'abord nos collections :
Code delphi : Sélectionner tout
1
2
3
4
5
Function TForm1.InitContexte( const strName: WideString; var varValue: OleVariant):TSWbemNamedValueSet; 
begin 
  Result:=TSWbemNamedValueSet.Create(Self); 
  Result.Add(strName,varValue,0) // IFlags tjr zéro 
end;
Le nom donné a la valeur nommée est identique mais pas son contenu :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure TForm1.FormCreate(Sender: TObject); 
Var value: OleVariant; 
begin 
 //Collection liée à la gestion des instances de process Win32. 
  //Contenu 
 Value:='Instances';  
  //'SinkName' est le nom de la valeur nommée et 'Instances' son contenu. 
 ProcessContext:=InitContexte('SinkName',Value); 
  
//Collection liée à la gestion de l'eventlog. 
 Value:='EventLog'; 
 EventLogContext:=InitContexte('SinkName',Value); 
end;
Une fois ceci fait, on associe un contexte à une requête de la manière suivante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var 
  Query: String; 
  Query2: String; 
  
begin 
  Query:='Select * from __InstanceDeletionEvent within 1 where TargetInstance isa "Win32_Process"'; 
  
     // On utilise le même collecteur pour 2 évènements différents 
     // On ajoute un objet TSWbemNamedValueSet afin de différencier l'événement. 
  WMIService.ExecNotificationQueryAsync(SWbemSink1.DefaultInterface, 
                                        Query, 
                                        'WQL', 
                                        wbemFlagSendStatus, 
                                        Nil, 
                                        ProcessContext.DefaultInterface);  
  
  Query2:='Select * from __InstanceCreationEvent where TargetInstance isa "Win32_NTLogEvent"'; 
  
  WMIService.ExecNotificationQueryAsync(SWbemSink1.DefaultInterface, 
                                        Query2, 
                                        'WQL', 
                                        wbemFlagSendStatus, 
                                        Nil, 
                                        EventLogContext.DefaultInterface); 
  
end;
On utilise donc un seul collecteur de données ( SWbemSink1) auquel on associe plusieurs requêtes WQL. Chaque requête portant un objet TSWbemNamedValueSet qui permettra de différencier le type d'événement reçu dans la méthode ObjectReady de notre collecteur de données.

Voici le code permettant de retrouver quel type d'évènement a été déclenché :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
procedure TForm1.SWbemSink1ObjectReady(ASender: TObject; 
  const objWbemObject: ISWbemObject; 
  const objWbemAsyncContext: ISWbemNamedValueSet); 
// Déclenché lorsqu'un objet fourni par l'appel asynchrone est disponible. 
// ObjWbemObject contient l'objet retourné 
  
var WmiObjet: ISWbemObject; 
    Contexte : ISWbemNamedValue; 
    WMILastError: TSWbemLastError; 
  
begin 
 If Not VarIsEmpty(objWbemAsyncContext) then 
  begin 
   try 
     Contexte:=objWbemAsyncContext.Item('SinkName',0); // IFlags tjr zéro 
      // Si l'item n'existe pas, renvoie=wbemErrNotFound 
   except 
     on E:Exception do 
      begin 
       if (E is EOleException) or (E is EOleSysError) then 
        begin 
         if ExistWMIErreur(WMILastError,Self) 
          then ShowWMIErreur('Collecteur événement onReady : Méthode Item .',WMILastError,(E as EOleException)); 
         Memo1.Lines.Add(#13#10+'Test d''item inexistant.'); 
         Memo1.Lines.Add(StrOriginError((E as EOleException).ErrorCode)); 
         Memo1.Lines.Add('Erreur ['+IntToHex((E as EOleException).ErrorCode,8)+'] '+E.Message); 
        end 
       else Raise; //On redéclenche l'exception inconnue 
      end; 
   end; //Except 
  
       // L'objet retourné contient une copie de l'instance de l'eventlog crée. 
       // TargetInstance est une propriété commune aux classes : 
       //                __InstanceCreationEvent 
       //                __InstanceDeletionEvent 
  
      WmiObjet:=IUnknown(objWbemObject.Properties_.Item('TargetInstance',0).Get_Value) as ISWbemObject; 
  
    If Contexte.Get_Value = 'Instances' 
     Then Memo1.Lines.Add(#13#10+'Le process '+WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value)+ 
                          ' s''est terminé.'+#13#10) 
     else 
       If Contexte.Get_Value = 'EventLog' 
        then Memo1.Lines.Add(#13#10+'Un événement vient d''être ajouté au journal des événements '+ 
			#13#10+WMIVariantToStr(WmiObjet.Properties_.Item('Message',0).Get_Value)) 
        else 
         begin 
          Memo1.Lines.Add('Contexte non géré.'); 
          Exit; 
         end; 
    Memo1.Lines.Add(WmiObjet.Path_.path); 
    Memo1.Lines.Add(AdjustLineBreaks(WmiObjet.GetObjectText_(0))); 
  end; 
  // Else 
  
  // 'Contexte' est une interface ISWbemNamedValue locale à cette procédure, Delphi 
  // se charge de décrémenter son compteur de référence. 
end;

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Il est parfois nécessaire de surveiller plusieurs types d'événement pouvant être générés par une seule requête :

Code delphi : Sélectionner tout
1
2
3
4
Const  
 cstWMIEvent: Array[0..2] of String=('__InstanceCreationEvent', 
                                     '__InstanceDeletionEvent', 
                                     '__InstanceModificationEvent');
Dans l'exemple suivant on souhaite retrouver tous les évènements liés à la manipulation d'un fichier :
Code delphi : Sélectionner tout
1
2
3
4
5
//On est informé d'une opération sur un fichier dans un directory, 
// les '\' sont dupliqués. 
  Query:='Select * from __InstanceOperationEvent within 1'+ 
         ' where TargetInstance ISA ''CIM_DataFile'''+ 
         ' and TargetInstance.name=''c:\\temp\\test.txt''';
Pour retrouver le nom de la classe de l'événement, on doit interroger la propriété Path_ de type SWbemObjectPath puis la propriété Class_ de type String :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Quelle requête gère-t-on ? 
      If Contexte.Get_Value = 'Fichier' 
       Then 
        begin 
           //On détermine le type de l'événement d'après son nom de classe 
         Case AnsiIndexStr(objWbemObject.Path_.Class_,cstWMIEvent) of 
          0 : Memo1.Lines.Add('Création'); 
          1 : Memo1.Lines.Add('Suppression'); 
          2 : Memo1.Lines.Add('Modification'); 
         end; 
          //Affiche le nom du fichier, déjà connu dans cet exemple 
         NomFichier:=WMIVariantToStr(WmiObjet.Properties_.Item('Name',0).Get_Value); 
         Memo1.Lines.Add(#13#10+'Fichier concerné : '+WMIGetNomFichier(NomFichier)+#13#10); 
        end
On peut donc avoir un collecteur de données unique (TSWbemSink) gérant plusieurs requêtes, chaque requête pouvant générer plusieurs types d'événement.

Mis à jour le 15 janvier 2014 Laurent Dardenne

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2020 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.