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

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 929, dernière mise à jour : 31 décembre 2023  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.

SommaireSystèmeWMIOpérations de base (12)
précédent sommaire suivant
 

Avant toute chose vous devez importer la librairie de type (fichier .TLB) qui se trouve dans le répertoire du référentiel WMI.

Code other : Sélectionner tout
1
2
3
Sous XP : 
C:\WINDOWS\system32\wbem\wbemdisp.tlb 
C:\WINDOWS\system32\wbem\wbemads.tlb (Pour manipuler Active Directory via WMI)
Utiliser pour ce faire le menu "Composant- Importer un contrôle ActiveX".

Une fois ceci fait vous disposerez d'une unité qui vous permettra d'accéder aux objets WMI. Cette unité se trouvera dans le répertoire ..\Delphi\Imports\xxxx_TLB.pas.
Cette unité est à ajouter systématiquement dans la clause uses pour tous les exemples concernant WMI présentés dans cette FAQ.

Pour se connecter à WMI on utilise un composant TSWbemLocator.
Sa méthode ConnectServer établit une connexion au référentiel WMI dans un espace de noms particulier. Dans l'exemple suivant on se connecte dans l'espace de noms 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éussit, elle renvoie un objet SWbemServices initialisé, sinon le traitement ne peut se poursuivre.

Cet objet SWbemServices nous permettra d'exécuter des opérations sur l'espace de noms courant.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
Si vous déposez un composant TSWbemLocator sur un fiche renseignez respectivement ses propriétés AutoConnect à false et Connectkind à ckRunningOrNew.

Ce code ne contient pas de test d'erreurs. Vous trouverez dans les codes sources proposés avec le second tutoriel sur WMI le projet 1-SWbemLastError\WbemLastError.dpr qui vous permettra de voir dans le détail la gestion des erreurs.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Vous pouvez utiliser les méthodes et les propriétés d'un objet SWbemObject pour représenter une définition de classe WMI ou une instance d'objet de n'importe quelle classe WMI.
L'objet que vous manipulez est une copie locale. Si vous souhaitez modifier l'objet dans le référentiel WMI, utilisez sa méthode put_.

Si vous voulez créer une nouvelle classe, utilisez SWbemServices.Get avec un nom de path vide. L'appel retourne un objet SWbemObject qui peut devenir une classe.

Vous pouvez renseigner un nom de classe dans la propriété de l'objet SWbemObjectPath retournée par l'appel de sa méthode Path_.
Vous pouvez ajouter des propriétés à la nouvelle classe par l'appel de la méthode Properties_.
Pour créer une instance d'une classe existante, appelez SWbemServices.SpawnInstance_.

Il ne faut pas confondre les objets des API WMI (SwbemLocator, SwbemObject, SwbemServices) et les classes d'objets ou les instances d'objets du référentiel WMI (Win32_Directory, Win32_Process…).
Les premiers de type TObject ou COM sont manipulables directement sous Delphi.

Exemple :

Code delphi : Sélectionner tout
WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '','', wbemConnectFlagUseMaxWait, nil);
Les seconds ne sont pas manipulables directement sous Delphi.
L'exemple suivant n'est pas possible :
Code delphi : Sélectionner tout
1
2
3
4
5
6
Var 
 NewProcess: Win32_Process; 
  
Begin 
 NewProcess:=Win32_Process.Create('Notepad.exe','c:\temp',Nil, ProcessId); 
End;
On doit impérativement utiliser un objet conteneur de type SwbemObject.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

De nombreux objets WMI renvoient des collections de données. Ces collections sont du type interface IEnumVariant (consultez ce lien pour plus de détails sur l'interface IENumVariant).

Le code suivant permet d'afficher toutes les sous-classes de l'espace de nom ROOT\CIMV2.

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
procedure TForm1.BTConnexionClick(Sender: TObject); 
var 
  WmiService:          SWbemServices; 
  
  WmiObject:           SWbemObject; 
  wmiObjectSet:        SWbemObjectSet; 
  
  WmiObjectPath:       SWbemObjectPath; 
  
  ObjectEnumerator:    IEnumVariant; 
  ArrayVariant:        OleVariant;  // Tableau de variant 
  NumberItem:          LongWord; 
  
  ClasseList:           TStringList; 
begin 
try 
   WMILocator:= TSWbemLocator.Create(self); 
    // crée une liste pour le tri 
    // permet de comparer le résultat avec celui des outils WMI de MS 
  ClasseList := TStringList.Create; 
  ClasseList.Sorted:=True; 
  
  Memo1.Lines.Clear; 
   // 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 objet SWbemServices 
   WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                         '', wbemConnectFlagUseMaxWait, nil); 
  
   // Retrouve la collection d'objet SWbemObject contenant toutes les sous-classes 
   // immédiates de l'espace de nom courant 
  WmiObjectSet:= WmiService.SubclassesOf('',wbemFlagReturnWhenComplete,Nil); 
                                           //+wbemQueryFlagShallow limite aux sous-Classes immédiates 
  
   // 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 l'objet SWbemObject courant de la collection 
   WmiObject := IUnknown(ArrayVariant) as SWBemObject; 
      // 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); 
  end; 
  Memo1.Lines.Assign(ClasseList); 
  Memo1.Lines.Add(#13#10+IntToStr(ClasseList.Count)+' Classes.'); 
  
 Finally 
  ClasseList.Free; 
 end; 
end;
Il est possible de trouver les propriétés de l'instance au format MOF (Managed Object Format) :
Code delphi : Sélectionner tout
Memo1.Lines.Add(AdjustLineBreaks(wmiObject.GetObjectText_(0)));
Sous Delphi 2005 et supérieur, vous pouvez encapsuler une interface IEnumVariant dans un itérateur.

Les objets se terminant par Set (SWbemXXXXXSet) proposent des collections d'objets, leur type étant indiqué dans le nom de l'objet.
Par exemple l'objet SwbemPropertySet contient un collection d'objets de type SwbemProperty.

Objets de type collection (enumerators) :
SwbemPropertySet, SWbemNamedValueSet, SWbemPrivilegeSet, SWbemQualifierSet, SWbemMethodSet

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Les propriétés sont des noms qui décrivent une ressource gérée. Les classes utilisent des propriétés pour décrire des choses comme l'identité, la configuration, et l'état d'une ressource gérée. Par exemple les services (Win32_Service) ont un nom, un nom d'affichage, une description, un type de démarrage, et un statut.

Chaque propriété a un nom, un type, et des qualificateurs de propriété facultatifs. Certaines propriétés peuvent être des clés permettant l'unicité sur des noms d'instance par exemple.

L'objet SWbemProperty représente une propriété d'un objet géré, on ne peut créer ce type d'objet.

  • CIMType
    Type de la propriété.
  • IsArray
    Indique si la propriété est un tableau.
  • IsLocal
    Indique si c'est une propriété locale.
    Une valeur False indique que la propriété est héritée d'une autre classe.
  • Name
    Nom de la propriété.
  • Origin
    Contient la classe d'origine de cette propriété. Recherche le nom de la classe de WMI dans laquelle cette propriété a été déclarée. Pour les classes avec des hiérarchies d'héritage profond, il est souvent souhaitable de connaître quelles propriétés ont été déclarées et dans quelle classe.
    Si la propriété est locale (voir SWbemQualifier.IsLocal), cette valeur est identique à la classe propriétaire.
  • Qualifiers_
    Objet de type SwbemQualiferSet, qui est une collection des qualificateurs de la propriété.
  • Value
    Valeur actuelle de la propriété. C'est la propriété d'automation par défaut de cet objet (c'est un objet de type variant)

Le code suivant énumère une collection et affiche pour chaque élément le nom de la propriété et son contenu :
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 WMIEnumereProperty( WmiService:SWbemServices; WmiPropertySet: SWbemPropertySet; Liste: TStrings); 
//Enumère une collection et affiche pour chaque élément le nom de la propriété et son contenu. 
//Détermine si le qualificateur Key de la propriété existe. 
var 
  WmiProperty :   SWBemProperty; 
  Enumerateur:    IEnumVariant; 
  ArrayVariant:   OleVariant;  // Tableau de variant 
  NombreItem:     LongWord; 
  KeyQualificateur: String; 
  
begin 
  Enumerateur:= (WmiPropertySet._NewEnum) as IEnumVariant; 
  while (Enumerateur.Next(1, ArrayVariant, NombreItem) = S_OK) do 
   begin 
    WmiProperty := IUnknown(ArrayVariant) as SWBemProperty; 
    KeyQualificateur:=WMIGet_KeyQualifierOfProperty(WmiService,WmiProperty); 
    If KeyQualificateur<>'' 
     then Liste.add('Clé ['+KeyQualificateur+'] = '+ 
                          WmiPropertySet.Item(KeyQualificateur,0).Get_Value); 
    Liste.Add(AdjustLineBreaks('Propriété '+WmiProperty.name+' = '+ 
              WMIPropertyToStr(WmiService,WmiProperty))); 
   end; 
end;
Consultez Comment convertir une propriété en chaîne de caractères ? pour retrouver le code de la fonction WMIPropertyToStr.

La procédure suivante recherche la qualificateur nommé 'Key'. Il indique que la propriété est une clef de classe et est employée pour identifier des instances uniques d'une ressource gérée dans une collection de ressources identiques.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function WMIGet_KeyQualifierOfProperty( WmiService:SWbemServices; WmiProperty: SWbemProperty):String; 
//Recherche pour une propriété le qualificateur KEY. 
//Cette clé déterminant l'unicité dans une classe d'association par exemple. 
  
begin 
 try 
  WmiProperty.Qualifiers_.Item('Key',0); 
  Result:=WmiProperty.name; // cette propriéte est une clé ( Key Qualifier) 
       // Une clé par propriété, mais plusieurs 
       // propriétés peuvent former une clé composée. 
 except 
  on E:EOleException do 
   Result:=''; 
 end; 
end;
Il est aussi possible d'utiliser la propriéte Path_.Keys. La valeur renvoyée est une collection du type SWbemNamedValueSet.

Note :
La fonction WMIGet_KeyQualifierOfProperty recherche pour une propriété le qualificateur KEY. Cette clé détermine par exemple l'unicité dans une classe d'association. Ce qualificateur peut ne pas exister, ce qui est souvent le cas. L'exception wbemErrNotFound (0x80041002) ou "Objet non-trouvé" est donc très souvent déclenchée dans l'EDI sans que cela soit à proprement parler une erreur.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Les qualificateurs sont des adjectifs qui fournissent des informations additionnelles au sujet de la classe, de la propriété ou de la méthode à laquelle ils s'appliquent. Par exemple le qualificateur de la classe nommé Dynamic répond à la question "Quel est le type de classe de Win32_Service ?".

Dans les premiers temps d'utilisation de WMI, vous rechercherez simplement des informations. Ensuite, si vous souhaitez modifier des propriétés ou appeler des méthodes, les qualificateurs deviennent de plus en plus importants car ils définissent les caractéristiques opérationnelles de la propriété que vous mettez à jour ou de la méthode que vous appelez.

Le code suivant énumère la liste des qualificateurs d'une instance :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
procedure WMIEnumereQualificateur( WmiQualifierSet: SWbemQualifierSet; Liste: TStrings); 
//Enumère une collection et affiche, pour chaque élément, le nom du qualificateur et son contenu. 
  
var 
  WmiQualifier:   SWBemQualifier; 
  Enumerateur:    IEnumVariant; 
  ArrayVariant:   OleVariant;  // Tableau de variant 
  NombreItem:     LongWord; 
  
begin 
   Enumerateur:= (WmiQualifierSet._NewEnum) as IEnumVariant; 
   while (Enumerateur.Next(1, ArrayVariant, NombreItem) = S_OK) do 
   begin 
    WmiQualifier := IUnknown(ArrayVariant) as SWbemQualifier; 
      // Retrouve le nom et la valeur du qualificateur. 
    Liste.Add('Nom du Qualificateur : '+WmiQualifier.Name+'='+WMIVariantToStr(WmiQualifier.Get_Value) ); 
   end; 
end;
Consultez Comment convertir une propriété en chaîne de caractères ? pour retrouver le code la fonction WMIVariantToStr.

Exemple d'appel :
Code delphi : Sélectionner tout
WMIEnumereQualificateur( WmiObject.Qualifiers_,Memo1.Lines);

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Un chemin d'objet d'instance décrit l'emplacement d'une instance d'une classe donnée dans un espace de nom spécifique.
À partir d'une instance de type SWBemObject on utilise sa propriété Path_ de type SWbemObjectPath qui représente son chemin d'accés dans le référentiel.

Sa propriété path_ affiche son chemin complet et sa propriété RelPath affiche son chemin relatif.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
procedure WMIEnumereObjetRelPath( WmiObjectSet: SWbemObjectSet; Liste: TStrings); 
//Enumère une collection et affiche, pour chaque élément, le chemin relatif. 
var 
  WmiObject:      SWbemObject; 
  Enumerateur:    IEnumVariant; 
  ArrayVariant:   OleVariant; 
  NombreItem:     LongWord; 
  
begin 
  Enumerateur:= (WmiObjectSet._NewEnum) as IEnumVariant; 
  while (Enumerateur.Next(1, ArrayVariant, NombreItem) = S_OK) do 
  begin 
   WmiObject := IUnknown(ArrayVariant) as SWBemObject; 
      //Affiche au format MOF 
   Liste.Add(WmiObject.Path_.RelPath); 
  end; 
end;

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Le membre SWbemProperty.CIMType d'une propriété détermine son type de donnée.

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Function WMIPropertyToStr(WmiService:SWbemServices; WmiProperty : SWbemProperty):String; 
//Convertit une propriété en chaîne de caractères. 
  
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 //Voir l'énumération WbemCimTypeEnum 
        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'; 
  
          // Caractère unicode 16 bit au format de caractère universel Set&#150;2 (UCS-2)  
        wbemCimtypeChar16, 
         // Chaîne de caractères unicode 
        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; 
          (* Voir note en fin de méthode *) 
        wbemCimtypeReference: begin 
                                // Récupére l'objet référencé 
                               WmiObjet:=WmiService.Get(Value,wbemFlagReturnWhenComplete,Nil); 
                               sValue:=AdjustLineBreaks(WmiObjet.GetObjectText_(0)) 
                              end; 
          (* Voir note en fin de méthode *) 
          //Renvoie le path de la propriété de type Objet 
        wbemCimtypeObject : begin 
                                 // Récupére l'objet imbriqué 
                                 // **Peut-il être un tableau d'objets ? 
                              WmiObjet:=IUnknown(WmiProperty.Get_Value) as SWbemObject ; 
                              sValue:=WmiObjet.Path_.Relpath; 
                           end; 
      end; // case 
     except 
      on E: EVariantError do 
       ShowMessage('WMIPropertyToStr : Erreur de conversion de variant'); 
     end; 
 Finally 
  Result:=sValue; 
 end; 
end;
Notes :

wbemCimtypeReference :
Le mot-clé référence MOF décrit un chemin d'objet et mappe un type automation VT_BSTR.
Le chemin d'objet peut être un chemin complet vers un serveur et un espace de nom, ou un chemin relatif vers un autre objet dans le même espace de nom.

wbemCimtypeObject :
Encapsulation d'objet dans une classe.
Un objet encapsulé est un objet d'une classe qui existe dans une déclaration de classe ou d'instance d'une autre classe.
Par exemple, la classe de Win32_SecurityDescriptor contient les objets inclus Win32_Trustee.
Chacun des objets de Win32_Trustee contient un objet Win32_ACE.
WMI ne limite pas la profondeur à laquelle une classe peut avoir des objets encapsulés.
Cependant, employer une autre conception, telle que créer une classe d'association peut rendre un schéma plus maniable.

La gestion des exceptions devra être adaptée à votre contexte d'utilisation. L'appel à Showmessage étant ici à titre indicatif.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Une instance représente un objet ou un élément du monde réel. Une instance est toujours créée à partir d'une classe représentant le template de l'objet réel. Par exemple, une instance de disque représente un disque réel et son template est défini par la classe Disk.

Le référentiel peut vous renvoyer toutes les instances d'une classe particulière. On utilise à cette fin la méthode InstancesOf de l'objet SWbemServices.

On lui passe en paramètre le nom de la la classe WMI( Win32_OperatingSystem), la profondeur ( wbemQueryFlagShallow), c'est à dire si on parcourt toute la hiérarchie de la classe ou non, et si on attend ou non la fin de l'appel( wbemFlagReturnWhenComplete).

Le dernier paramètre peut être utilisé pour récupérer des instances partielles, c'est à dire que WMI renverra seulement les propriétés indiquées dans l'objet SWbemNamedValueSet. Ceci pouvant réduire l'occupation mémoire et le trafic réseau lors d'appel distant.

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
procedure TForm1.BTConnexionClick(Sender: TObject); 
var 
  WMILocator:          TSWbemLocator; 
  WmiService:          SWbemServices; 
  
  WmiObject:           SWbemObject; 
  wmiObjectSet:        SWbemObjectSet; 
  
  ObjectEnumerator:    IEnumVariant; 
  ArrayVariant:        OleVariant;   
  NumberItem:          LongWord; 
  
begin 
  WMILocator:= TSWbemLocator.Create(self); 
 try 
   WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                         '', wbemConnectFlagUseMaxWait, nil); 
  
   // Retrouve la collection d'instance de la classe Win32_OperatingSystem 
   // de l'espace de nom courant 
    wmiObjectSet := wmiService.InstancesOf('Win32_OperatingSystem', 
                                             wbemFlagReturnWhenComplete+wbemQueryFlagShallow, 
                                             nil); 
  
  ObjectEnumerator:= (WmiObjectSet._NewEnum) as IEnumVariant; 
  
  while (ObjectEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do 
  begin 
   WmiObject := IUnknown(ArrayVariant) as SWBemObject; 
  
      // Retrouve la propriété de l'instance au format MOF 
   Memo1.Lines.Add(AdjustLineBreaks(wmiObject.GetObjectText_(0))); 
  end; 
 Finally 
  WMILocator.Free; 
 end; 
end;

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

On utilise l'objet ISWbemNamedValue, il représente une valeur simple nommée qui appartient à une collection SWbemNamedValueSet.
L'objet ISWbemNamedValue n'a pas de méthode.
Les méthodes et propriétes de l'objet SWbemNamedValueSet sont principalement utilisées pour envoyer des informations supplémentaires aux providers lors de certains appels vers WMI.

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
59
60
61
62
63
64
65
66
67
68
69
70
71
procedure TForm1.btInstancePartielClick(Sender: TObject); 
 // Retrouve une instance partielle 
var 
  WMILocator:          TSWbemLocator; 
  WmiService:          SWbemServices; 
  
  WmiObject:           SWbemObject; 
  
  WmiProperty:         SWbemProperty; 
  WmiPropertySet:      SWbemPropertySet; 
  
  WmiNamedValueSet:    TSWbemNamedValueSet; 
  
  PropertyEnumerator:  IEnumVariant; 
  ArrayVariant:        OleVariant; 
  NumberItem:          LongWord; 
  
  Value:               Olevariant; 
  
begin 
try 
  WMILocator:= TSWbemLocator.Create(self); 
  
   // 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 objet SWbemServices 
  WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                         '', wbemConnectFlagUseMaxWait, nil); 
  
  WmiNamedValueSet:= TSWbemNamedValueSet.Create(self); 
  
  Value:=True; //Contenu de la valeur nommée 
   //'__GET_EXTENSIONS' signale une instance partielle 
  WmiNamedValueSet.Add('__GET_EXTENSIONS',Value,0); // iFlags toujours à zéro. 
  WmiNamedValueSet.Add('__GET_EXT_CLIENT_REQUEST',Value,0); 
  // WmiNamedValueSet.Add(' __GET_EXT_KEYS_ONLY',Value,0); //Renvoie seulement les clés 
  
   //Tableaux des propriétés à renvoyer 
  Value:=VarArrayCreate([1,2], varOleStr); 
  Value[1]:='Name'; 
  Value[2]:='State'; 
   //'__GET_EXT_PROPERTIES' indique la liste des propriétés à renvoyer 
  WmiNamedValueSet.Add('__GET_EXT_PROPERTIES',Value,0); 
  
   // Retrouve l'instance du service Telnet de la classe Win32_Service 
   // de l'espace de nom courant 
  WmiObject := wmiService.Get('Win32_Service.Name="TlntSvr"', 
                              0, 
                              WmiNamedValueSet.DefaultInterface); 
  
      // Retrouve la collection d'objets WmiProperty contenant toutes les propriétés 
   WmiPropertySet:= WmiObject.Properties_; 
   Memo1.Lines.Add(IntToStr(WmiPropertySet.Count)); 
      // Affecte un énumérateur pour la collection d'objets WmiProperty 
   PropertyEnumerator:= (WmiPropertySet._NewEnum) as IEnumVariant; 
  
   while (PropertyEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do 
   begin 
     // Récupére l'objet SWBemProperty courant de la collection 
    WmiProperty := IUnknown(ArrayVariant) as SWBemProperty; 
  
      // Retrouve le nom et la valeur de la propriété. 
   if not VarIsNull(WmiProperty.Get_Value) 
     then Memo1.Lines.Add(WmiProperty.name+'='+WMIPropertyToStr(WmiService,WmiProperty)); 
   end; 
  
 Finally 
  WmiNamedValueSet.Free; 
  WMILocator.Free; 
 end; 
end;
Vous trouverez le détail des valeurs nommées dans le lien ci-dessous.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

L'exemple suivant ne fait qu'imbriquer des appels d'énumérateurs et affiche la propriété 'Name' des instances de la classe Win32_Service, i.e. le nom du service.

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
procedure TForm1.BTConnexionClick(Sender: TObject); 
var 
  WMILocator:          TSWbemLocator; 
  WmiService:          SWbemServices; 
  
  WmiObject:           SWbemObject; 
  wmiObjectSet:        SWbemObjectSet; 
  
  WmiProperty:         SWbemProperty; 
  WmiPropertySet:      SWbemPropertySet; 
  
  PropertyEnumerator, 
  ObjectEnumerator:    IEnumVariant; 
  ArrayVariant:        OleVariant;  // Tableau de variant 
  NumberItem:          LongWord; 
  
begin 
  WMILocator:= TSWbemLocator.Create(self); 
 try 
   WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                         '', wbemConnectFlagUseMaxWait, nil); 
  
   // Retrouve la collection d'instances de la classe Win32_Service 
   // de l'espace de nom courant 
    wmiObjectSet := wmiService.InstancesOf('Win32_Service', 
                                             wbemFlagReturnWhenComplete+wbemQueryFlagShallow, 
                                             nil); 
  
  ObjectEnumerator:= (WmiObjectSet._NewEnum) as IEnumVariant; 
  
  while (ObjectEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do 
  begin 
   WmiObject := IUnknown(ArrayVariant) as SWBemObject; 
  
      // Retrouve la collection d'objets WmiProperty contenant toutes les propriétés 
   WmiPropertySet:= WmiObject.Properties_; 
      // Affecte un énumérateur pour la collection d'objet WmiProperty 
   PropertyEnumerator:= (WmiPropertySet._NewEnum) as IEnumVariant; 
  
     // Aprés l'affectation précédente, on peut réutiliser la variable ArrayVariant 
   while (PropertyEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do 
   begin 
     // Récupére l'objet SWBemProperty courant de la collection 
    WmiProperty := IUnknown(ArrayVariant) as SWBemProperty; 
  
       // Retrouve le nom du service via la propriété de classe nommée 'Name'. 
       // Implicite : propriété de type Chaine de caractéres. 
       //   WmiProperty.CIMType = wbemCimtypeString 
    If WmiProperty.name='Name' 
     then Memo1.Lines.Add(WmiProperty.Get_Value); 
   end; 
  end;  
 Finally 
  WMILocator.Free; 
 end; 
end;
Sous Delphi 2005 l'utilisation d'un itérateur simplifie le code :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Affecte un énumérateur pour la collection d'objet SWbemObjectSet 
  ObjectEnumerator:=TEnumVariant.Create(wmiService.InstancesOf('systemrestore', 
                                             wbemFlagReturnWhenComplete+wbemQueryFlagShallow, 
                                             nil)); 
  
  For MonObjetWMI in ObjectEnumerator do 
  begin 
      // Affecte un énumérateur pour la collection d'objets SWbemPropertySet 
   PropertyEnumerator:= TEnumVariant.Create((MonObjetWMI as SWBemObject).Properties_); 
  
   For MaProprieteWMI in PropertyEnumerator do 
   begin 
       // Retrouve le nom du service via la propriété de classe nommée 'Name'. 
    With (MaProprieteWMI as SWBemProperty)  do 
     begin 
      If Name='Name' 
 ...

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Vous pouvez employer les propriétés de l'objet SWbemMethod pour inspecter la définition d'une méthode d'un objet WMI.
Cet objet ne peut pas être créé.

Pour appeler une méthode, vous devez employer soit l'accès direct (SWbemObject.ExecMethod_) sur un objet de type SWbemObject (mode recommandé) soit l'appel indirect via la méthode SWbemServices.ExecMethod.

L'exemple suivant crée un process, notepad.exe, en exécutant la méthode Create de la classe Win32_Process.

Note :
Les variables BTDeleteProcess et BTCreateProcess référencent des composants TButton qui autorisent ou non la création d'un process unique via l'IHM.

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
var  ProcessID:   OleVariant; //Variable Globale 
... 
procedure TForm1.BTCreateProcessClick(Sender: TObject); 
var 
  WMILocator : TSWbemLocator; 
  
  Process, 
  NewProcess, 
  Instance_inParameters : SWbemObject; 
  
  WmiProperty : SWbemProperty; 
  
  ProcessMethod : ISWbemMethod; 
  
  PropertyCommandLine, 
  PropertyReturnValue : OleVariant; 
  
begin 
  WMILocator:= TSWbemLocator.Create(self); 
 try 
   WmiService:= WMILocator.ConnectServer('.', 'ROOT\CIMV2', '', '', '', 
                                         '', wbemConnectFlagUseMaxWait, nil); 
  
    // Retrouve la définition de la classe Win32_Process 
   Process:=WmiService.Get('Win32_Process',0,Nil); 
  
    // Récupère, à partir de la collection de méthode, 
    // la définition de la méthode 'Create' de la classe Win32_Process 
   ProcessMethod:=Process.Methods_.Item('Create', 0); 
    // La définition de la méthode 'Create' correspond à  : 
          {    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 ; 
          } 
  
    // 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); 
  
    // L'appel suivant est possible : 
    //   NewInParametersInstance:= Process.Methods_.Item('Create',0).inParameters.SpawnInstance_(0); 
  
    // Retrouve la propriété 'CommandLine' de la méthode '.Create' 
   WmiProperty:= Instance_inParameters.Properties_.Item('CommandLine',0); 
     // Nom du programme à 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 } 
  
    // Recupère la valeur de retour de la méthode via la propriété 'ReturnValue' 
   PropertyReturnValue:= NewProcess.Properties_.Item('ReturnValue', 0); 
   {Code de retour : 
     0 Successful completion 
     2 Access denied 
     3 Insufficient privilege 
     8 Unknown failure 
     9 Path not found 
     21 Invalid parameter 
    } 
  
   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); 
      BTDeleteProcess.Enabled:= True; 
      BTCreateProcess.Enabled:= False; 
      SetForegroundWindow(Form1.Handle); 
     end 
    else // Une erreur lors de la création du process 
     MessageBox(0, PChar('Erreur '+inttostr(PropertyReturnValue.Value)+' lors de la création du process.'), 
                PChar(Form1.Caption), MB_OK); 
 Finally 
  WMILocator.Free; 
 end; 
end;
Le code suivant supprime le process précédemment créé :
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
var 
  Instance_inParameters : SWbemObject; 
  WmiProperty : SWbemProperty; 
  ProcessMethod : ISWbemMethod; 
  PropertyReturnValue : OleVariant; 
  ObjectWmi, ParametreOut : SWBemObject; 
  PropertyReason : OleVariant; 
begin 
     // Retrouve une instance de la classe Win32_Process 
     // la propriété Handle est la clé de la classe 
    ObjectWmi:= WmiService.Get('Win32_Process.Handle="' + inttostr(ProcessId)+ '"', 0, nil); 
  
      // Retrouve la méthode Terminate 
    ProcessMethod:= ObjectWmi.Methods_.Item('Terminate', 0); 
    Instance_inParameters:= ProcessMethod.InParameters.SpawnInstance_(0); 
     // La méthode Terminate a 1 paramètre nommé Reason 
     //  Reason : [in] Exit code for the process and for all threads terminated as a result of this call. 
    WmiProperty:= Instance_inParameters.Properties_.Item('Reason',0); 
    PropertyReason:= 0; 
    WmiProperty.Set_Value(PropertyReason); 
  
     // Execute la méthode 
    ParametreOUT:= ObjectWmi.ExecMethod_('Terminate', Instance_inParameters, wbemFlagReturnWhenComplete, nil); 
     // Récupére le code de sortie 
    PropertyReturnValue:= ParametreOUT.Properties_.Item('ReturnValue', 0); 
    if PropertyReturnValue.Value = 0 then 
    begin 
      BTCreateProcess.Enabled:= True; 
      BTDeleteProcess.Enabled:= False; 
    end 
    else 
      MessageBox(0, PChar('Supression du process impossible.'), PChar(Form1.Caption), MB_OK); 
end;

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

Cet exemple a été testé avec un compte autorisé, en l'occurrence avec le compte administrateur.

L'accès à certaines classes ou données WMI exige un privilège qui n'est pas activé par défaut. Par exemple pour utiliser la classe Win32_NTEventlogFile vous devez inclure le privilège wbemPrivilegeSecurity.

Note :
Ce privilège n'ajoute pas de droit au compte utilisé lors de l'opération.

On utilise sur un objet SWbemServices sa propriété Security_ qui est du type SWbemSecurity.
On ajoute le privilège via la méthode Add de la propriété Privileges qui est une collection de privilèges.

Code delphi : Sélectionner tout
1
2
//Ajoute au process appelant le privilège wbemPrivilegeShutdown (SE_SHUTDOWN_NAME) 
  wmiService.Security_.Privileges.Add(wbemPrivilegeShutdown, True);
L'exemple suivant permet d'effecteur un Shutdown d'une machine locale ou distante :
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
procedure TForm1.BtConnexionClick(Sender: TObject); 
  
var 
  WmiService:          SWbemServices; 
  
  WmiObjet:            SWbemObject; 
  wmiObjetSet:         SWbemObjectSet; 
  
  WmiProperty:         SWbemProperty; 
  
  ObjectEnumerator:    IEnumVariant; 
  ArrayVariant:        OleVariant;  // Tableau de Variant 
  NumberItem:          LongWord; 
  
  ShutdownMethod_inParameters, 
  Shutdown :           SWbemObject; 
  
  PropertyReboot :     OleVariant; 
  
  ShutdownMethod:      SWbemMethod; 
  
  WMILocator:          TSWbemLocator; 
  
begin 
 WMILocator:= TSWbemLocator.Create(self); 
    // Initialisation 
  try 
     //Permet aux objets d'utiliser l'identité de l'appelant.  
     //C'est le niveau d'usurpation d'identité recommandé  
     //pour l'appel d'API de scripting WMI. 
  WMILocator.Security_.Set_ImpersonationLevel(wbemImpersonationLevelImpersonate ); 
  
     //WMI utilise la configuration d'authentification par défaut de Windows. 
  WMILocator.Security_.Set_AuthenticationLevel(wbemAuthenticationLevelDefault); 
  
    // Attention aux majuscules-minuscules pour le password. 
  WmiService:= WMILocator.ConnectServer('NomDeMachine', 
                                        'ROOT\CIMV2',  
                                        'MonDomaine\MonCompte',  
                                         'PasswordDuCompte',  
                                         '', 
                                         '', 
                                         wbemConnectFlagUseMaxWait, 
                                         nil); 
  except 
   on E:EOleException do 
    begin 
     // S'il s'agit d'un problème de mot de passe E_ACCESSDENIED=$80070005  
     ShowMessage(StrOriginError(E.ErrorCode)+' ['+IntToHex(E.ErrorCode,8)+'] '+E.Message); 
     Raise; 
    end; 
  end; 
  
    //Ajoute au process appelant le privilège wbemPrivilegeShutdown (SE_SHUTDOWN_NAME) 
  wmiService.Security_.Privileges.Add(wbemPrivilegeShutdown, True); 
  
  wmiObjetSet := wmiService.ExecQuery( 
    'SELECT * FROM Win32_OperatingSystem WHERE Primary=True', 
    'WQL', wbemFlagReturnImmediately, nil); 
  
  ObjectEnumerator:= (WmiObjetSet._NewEnum) as IEnumVariant; 
  
  while (ObjectEnumerator.Next(1, ArrayVariant, NumberItem) = S_OK) do 
  begin 
    WmiObjet := IUnknown(ArrayVariant) as SWBemObject; 
    ShutdownMethod:= wmiObjet.Methods_.Item('Win32Shutdown', 0); 
    ShutdownMethod_inParameters:= ShutdownMethod.InParameters; 
    Shutdown:= ShutdownMethod_inParameters.SpawnInstance_(0); 
    WmiProperty := Shutdown.Properties_.Add('Flags', wbemCimtypeSint32, False, 0); 
    PropertyReboot:= EWX_SHUTDOWN; // ou EWX_REBOOT; 
    wmiProperty.Set_Value(PropertyReboot); 
  
    wmiObjet.ExecMethod_('Win32Shutdown', Shutdown, 0, nil); 
  end; 
end;
Consultez la rubrique La gestion des erreurs WMI pour retrouver le code la fonction StrOriginError.

Notes :
Par défaut, tous les membres du groupe d'utilisateur local sur les systèmes Windows NT/Windows 2000 ont le droit d'accès en lecture seule sur tous les espaces de noms.
Pour modifier les permissions d'accès par défaut sout NT, il faut utiliser l'application Wbemcntl.exe et MMC sous Windows 2000.

Mis à jour le 15 janvier 2014 Laurent Dardenne Pedro

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 © 2024 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.