浏览代码

[wmi] recfactorized and improved classes

Exilon 5 年之前
父节点
当前提交
6cd3daf229
共有 1 个文件被更改,包括 212 次插入53 次删除
  1. 212 53
      Quick.WMI.pas

+ 212 - 53
Quick.WMI.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2019 Kike Pérez
+  Copyright (c) 2016-2020 Kike Pérez
 
   Unit        : Quick.WMI
   Description : Common functions
   Author      : Kike Pérez
-  Version     : 1.0
+  Version     : 1.1
   Created     : 04/04/2019
-  Modified    : 08/04/2019
+  Modified    : 22/04/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -40,47 +40,99 @@ interface
 
 uses
   SysUtils,
-  WbemScripting_TLB,
   ActiveX,
   ComObj,
+  Quick.Commons,
+  Quick.Collections,
   Quick.Arrays,
   Quick.Value,
   Variants;
 
 type
 
-  TFlexArray = TArray<TFlexValue>;
+  IWMIInstance = interface
+  ['{4C81A6A6-4A65-46FB-B05B-5898DF51F9B7}']
+    function GetProperty(const aPropertyName : string) : TFlexValue;
+    function GetProperties(const aProperties : TArray<string>) : IList<TFlexPair>;
+    function GetName : string;
+  end;
 
-  TWMIObject = record
+  TWMIInstance = class(TInterfacedObject,IWMIInstance)
   private
     fInstance : string;
-    fProperty : string;
+    fWMIItem : OleVariant;
+  public
+    constructor Create(const aInstanceName : string; aWMIItem: OleVariant);
+    destructor Destroy; override;
+    function GetProperty(const aPropertyName : string) : TFlexValue;
+    function GetProperties(const aProperties : TArray<string>) : IList<TFlexPair>;
+    function GetName : string;
   end;
 
-  TWMICollector = class
-  private
-    class function GetObject(const aObjectName: string) : IDispatch;
-  public
-    class function GetProperty(const aWMIHost, aRoot, aWMIClass, aWMIProperty : string) : TFlexValue;
-    class function GetPropertyInstances(const aWMIHost, aRoot, aWMIClass,aWMIProperty : string; const aInstances : string = '*') : TFlexPairArray;
+  TWMIInstances = TArray<IWMIInstance>;
+
+  IWMIClass = interface
+  ['{FAFE26ED-28BC-4591-AE5A-9E4543074B5C}']
+    function GetInstance(const aInstance : string) : IWMIInstance;
+    function GetInstances(const aInstances : TArray<string>) : TWMIInstances;
   end;
 
-  TWMIInstance = class
+  TWMIClass = class(TInterfacedObject,IWMIClass)
   private
-    fInstance : string;
+    fClassName : string;
+    fWMIService : OleVariant;
+    fWMIClassItems : IEnumvariant;
+    function GetInstanceName(aWMIClass : OleVariant) : string;
   public
-    property Instance : 
+    constructor Create(aWMIService : OleVariant; const aClassName : string; aWMIClassItems : IEnumvariant);
+    destructor Destroy; override;
+    function GetInstance(const aInstance : string) : IWMIInstance;
+    function GetInstances(const aInstances : TArray<string>) : TWMIInstances;
   end;
 
-  TWMIObject2 = class
+  IWMICollector = interface
+  ['{3FFFF0DC-F533-4FE1-A511-73E76EC6BCC8}']
+    function From(const aRoot, aWMIClass : string) : IWMIClass; overload;
+    function From(const aHost, aRoot, aWMIClass : string) : IWMIClass; overload;
+  end;
+
+  TWMICollector = class(TInterfacedObject,IWMICollector)
+  private
+    fNamespace : string;
+    fWMIService : OleVariant;
   public
-    function FromInstance(const aInstanceName : string) : TWMIInstance;
+    constructor Create;
+    destructor Destroy; override;
+    class function GetObject(const aObjectName: string) : IDispatch;
+    function From(const aRoot, aWMIClass : string) : IWMIClass; overload;
+    function From(const aHost, aRoot, aWMIClass : string) : IWMIClass; overload;
   end;
 
   EWMICollector = class(Exception);
 
 implementation
 
+const
+  wbemFlagUseAmendedQualifiers = $00020000;
+  wbemFlagReturnImmediately    = $00000010;
+  wbemFlagReturnWhenComplete   = $00000000;
+  wbemFlagForwardOnly          = $00000020;
+
+{ TWMICollector }
+
+constructor TWMICollector.Create;
+begin
+  fNamespace := '';
+  CoInitialize(nil);
+end;
+
+destructor TWMICollector.Destroy;
+begin
+  fWMIService := Unassigned;
+  CoUninitialize;
+  inherited;
+end;
+
 class function TWMICollector.GetObject(const aObjectName: string) : IDispatch;
 var
   chEaten : Integer;
@@ -92,59 +144,166 @@ begin
   OleCheck(Moniker.BindToObject(bindCtx, nil, IDispatch, Result));
 end;
 
-class function TWMICollector.GetProperty(const aWMIHost, aRoot, aWMIClass, aWMIProperty: string) : TFlexValue;
+function TWMICollector.From(const aRoot, aWMIClass : string) : IWMIClass;
+begin
+  Result := From('.',aRoot,aWMIClass);
+end;
+
+function TWMICollector.From(const aHost, aRoot, aWMIClass : string) : IWMIClass;
 var
-  objWMIService : OLEVariant;
   colItems : OLEVariant;
-  colItem : OLEVariant;
   oEnum : IEnumvariant;
-  iValue : LongWord;
 begin
-  CoInitialize(nil);
   try
+    //only connect if namespace is different from previous connection
+    if fNamespace <> aHost + '\' + aRoot then
+    begin
+      fWMIService := GetObject(Format('winmgmts:\\%s\%s',[aHost,aRoot]));
+      fNamespace := aHost + '\' + aRoot;
+    end;
+    colItems := fWMIService.ExecQuery(Format('SELECT * FROM %s',[aWMIClass]),'WQL',wbemFlagForwardOnly and wbemFlagReturnImmediately);
+    oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
+    Result := TWMIClass.Create(fWMIService,aWMIClass,oEnum);
+  except
+    on E : Exception do raise EWMICollector.CreateFmt('Error getting WMI Class "\\%s\%s\%s": %s',[aHost,aRoot,aWMIClass,e.Message]);
+  end;
+end;
+
+{ TWMIInstance }
+
+constructor TWMIInstance.Create(const aInstanceName : string; aWMIItem: OleVariant);
+begin
+  fInstance := aInstanceName;
+  fWMIItem := aWMIItem;
+end;
+
+destructor TWMIInstance.Destroy;
+begin
+  fWMIItem := Unassigned;
+  inherited;
+end;
+
+function TWMIInstance.GetName: string;
+begin
+  Result := fInstance;
+end;
+
+function TWMIInstance.GetProperties(const aProperties : TArray<string>) : IList<TFlexPair>;
+var
+  prop : string;
+begin
+  Result := TxList<TFlexPair>.Create;
+  for prop in aProperties do
+  begin
     try
-      objWMIService := GetObject(Format('winmgmts:\\%s\%s',[aWMIHost,aRoot]));
-      colItems := objWMIService.ExecQuery(Format('SELECT * FROM %s',[aWMIClass]),'WQL',0);
-      oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
-      while oEnum.Next(1, colItem, iValue) = 0 do
-      begin
-        Result := colItem.Properties_.Item(aWMIProperty, 0);
-        Break;
-      end;
+      Result.Add(TFlexPair.Create(prop,fWMIItem.Properties_.Item(prop, 0)));
     except
-      on E : Exception do raise EWMICollector.CreateFmt('Error getting WMI property: %s',[e.Message]);
+      on E : Exception do raise EWMICollector.CreateFmt('Retrieving "%s" (%s)',[prop,e.message]);
     end;
-  finally
-    CoUninitialize;
   end;
 end;
 
-class function TWMICollector.GetPropertyInstances(const aWMIHost, aRoot, aWMIClass,aWMIProperty : string; const aInstances : string = '*') : TFlexPairArray;
+function TWMIInstance.GetProperty(const aPropertyName: string): TFlexValue;
+begin
+  Result := fWMIItem.Properties_.Item(aPropertyName, 0);
+end;
+
+{ TWMIClass }
+
+constructor TWMIClass.Create(aWMIService : OleVariant; const aClassName : string; aWMIClassItems : IEnumvariant);
+begin
+  fWMIService := aWMIService;
+  fClassName := aClassName;
+  fWMIClassItems := aWMIClassItems;
+end;
+
+destructor TWMIClass.Destroy;
+begin
+  //fWMIClassItems := nil;
+  fWMIService := Unassigned;
+  inherited;
+end;
+
+function TWMIClass.GetInstance(const aInstance: string): IWMIInstance;
 var
-  objWMIService : OLEVariant;
-  colItems : OLEVariant;
-  colItem : OLEVariant;
-  oEnum : IEnumvariant;
+  propItem : OLEVariant;
   iValue : LongWord;
+  instanceName : string;
 begin
-  CoInitialize(nil);
-  try
+  while fWMIClassItems.Next(1, propItem, iValue) = 0 do
+  begin
+    instanceName := GetInstanceName(propItem);
     try
-      objWMIService := GetObject(Format('winmgmts:\\%s\%s',[aWMIHost,aRoot]));
-      colItems := objWMIService.ExecQuery(Format('SELECT * FROM %s',[aWMIClass]),'WQL',0);
-      oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
-      while oEnum.Next(1, colItem, iValue) = 0 do
+      if CompareText(aInstance,instanceName) = 0 then
       begin
-        if (aInstances = '*') or (CompareText(aInstances,colItem.Name) = 0)  then
-        begin
-          Result.Add(colItem.Name,colItem.Properties_.Item(aWMIProperty, 0));
-        end;
+        Result := TWMIInstance.Create(instanceName,propItem);
+        Break;
       end;
-    except
-      on E : Exception do raise EWMICollector.CreateFmt('Error getting WMI property: %s',[e.Message]);
+    finally
+      propItem := Unassigned;
+    end;
+  end;
+end;
+
+function TWMIClass.GetInstanceName(aWMIClass : OleVariant) : string;
+var
+  qualifiers : OleVariant;
+  enumQualif : IEnumVariant;
+  qualifItem : OleVariant;
+  pceltFetched : Cardinal;
+  propItem : OleVariant;
+  enumProp : IEnumVariant;
+  iValue : Cardinal;
+  properties : OleVariant;
+  objSWbemObjectSet : OleVariant;
+begin
+  Result := '';
+  objSWbemObjectSet:= fWMIService.Get(fClassName, wbemFlagUseAmendedQualifiers and wbemFlagReturnWhenComplete);
+  properties := objSWbemObjectSet.Properties_;
+  enumProp := IUnknown(properties._NewEnum) as IENumVariant;
+  while enumProp.Next(1, propItem, iValue) = 0 do
+  begin
+    qualifiers := propItem.Qualifiers_;
+    enumQualif := IUnknown(qualifiers._NewEnum) as IEnumVariant;
+    //iterate over the qualifiers
+    while enumQualif.Next(1, qualifItem, pceltFetched) = 0 do
+    begin
+      //check the name of the qualifier
+      //Result := rgvarQualif.Name;
+      //Result := rgvarQualif.Value;
+      if qualifItem.Name = 'key' then
+      begin
+        if qualifItem.Value then if Result = '' then Result := aWMIClass.Properties_.Item(propItem.Name,0)
+          else Result := Format('%s %s',[Result,aWMIClass.Properties_.Item(propItem.Name,0)]);
+      end;
+      //VarClear(qualifItem);
+      qualifItem := Unassigned;
+    end;
+    //enumQualif := nil;
+    qualifiers := Unassigned;
+    propItem := Unassigned;
+  end;
+  //enumProp := nil;
+  properties := Unassigned;
+  objSWbemObjectSet := Unassigned;
+end;
+
+function TWMIClass.GetInstances(const aInstances: TArray<string>): TWMIInstances;
+var
+  propItem : OLEVariant;
+  iValue : LongWord;
+  getAllInstances : Boolean;
+  instanceName : string;
+begin
+  getAllInstances := (High(aInstances) = 0) and (aInstances[0] = '*');
+  while fWMIClassItems.Next(1, propItem, iValue) = 0 do
+  begin
+    instanceName := GetInstanceName(propItem);
+    if (getAllInstances) or (StrInArray(instancename,aInstances)) then
+    begin
+      Result := Result + [TWMIInstance.Create(instanceName,propItem)];
     end;
-  finally
-    CoUninitialize;
+    propItem := Unassigned;
   end;
 end;