The Road to Delphi

Delphi – Free Pascal – Oxygene


9 Comments

Exploring Delphi XE3 – WinApi Additions – Winapi.Wbem

Delphi XE3 introduces a lot of new WinApi headers translations, between them is the Winapi.Wbem unit which is the Delphi (object pascal) translation for the wbemidl.h file which contains the WMI Component Object Model (COM) interface definitions. This means that from now you can access the WMI in a fastest way and directly using COM avoiding the use of the Microsoft WMIScripting Library and third party libraries.

Try this sample Delphi XE3 console application which access the Win32_Process WMI Class using the Winapi.Wbem unit.

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Winapi.Windows,
  System.SysUtils,
  Winapi.ActiveX,
  Winapi.Wbem;

const
  //Impersonation Level Constants
  //http://msdn.microsoft.com/en-us/library/ms693790%28v=vs.85%29.aspx
  RPC_C_AUTHN_LEVEL_DEFAULT   = 0;
  RPC_C_IMP_LEVEL_ANONYMOUS   = 1;
  RPC_C_IMP_LEVEL_IDENTIFY    = 2;
  RPC_C_IMP_LEVEL_IMPERSONATE = 3;
  RPC_C_IMP_LEVEL_DELEGATE    = 4;

  //Authentication Service Constants
  //http://msdn.microsoft.com/en-us/library/ms692656%28v=vs.85%29.aspx
  RPC_C_AUTHN_WINNT      = 10;
  RPC_C_AUTHN_LEVEL_CALL = 3;
  RPC_C_AUTHN_DEFAULT    = Longint($FFFFFFFF);
  EOAC_NONE              = 0;

  //Authorization Constants
  //http://msdn.microsoft.com/en-us/library/ms690276%28v=vs.85%29.aspx
  RPC_C_AUTHZ_NONE       = 0;
  RPC_C_AUTHZ_NAME       = 1;
  RPC_C_AUTHZ_DCE        = 2;
  RPC_C_AUTHZ_DEFAULT    = Longint($FFFFFFFF);

  //Authentication-Level Constants
  //http://msdn.microsoft.com/en-us/library/aa373553%28v=vs.85%29.aspx
  RPC_C_AUTHN_LEVEL_PKT_PRIVACY   = 6;
  SEC_WINNT_AUTH_IDENTITY_UNICODE = 2;

 //COAUTHIDENTITY Structure
 //http://msdn.microsoft.com/en-us/library/ms693358%28v=vs.85%29.aspx
 type
    PCOAUTHIDENTITY    = ^TCOAUTHIDENTITY;
    _COAUTHIDENTITY    = Record
                          User           : PChar;
                          UserLength     : ULONG;
                          Domain         : PChar;
                          DomainLength   : ULONG;
                          Password       : PChar;
                          PassWordLength : ULONG;
                          Flags          : ULONG;
                          End;

   COAUTHIDENTITY      = _COAUTHIDENTITY;
   TCOAUTHIDENTITY     = _COAUTHIDENTITY;



function GetExtendedErrorInfo(hresErr: HRESULT):Boolean;
var
 pStatus    : IWbemStatusCodeText;
 hres       : HRESULT;
 MessageText: WideString;
begin
  Result:=False;
    hres := CoCreateInstance(CLSID_WbemStatusCodeText, nil, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText, pStatus);
    if (hres = S_OK) then
    begin
     hres := pStatus.GetErrorCodeText(hresErr, 0, 0, MessageText);
     if(hres <> S_OK) then
       MessageText := 'Get last error failed';

     Result:=(hres = S_OK);
     if Result then
      Writeln(Format( 'ErrorCode %x Description %s',[hresErr,MessageText]));
    end;
end;


procedure  TestWbem;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  WbemLocale          ='';
  WbemAuthority       ='kERBEROS:'+WbemComputer;
var
  LWbemLocator         : IWbemLocator;
  LWbemServices        : IWbemServices;
  LUnsecuredApartment  : IUnsecuredApartment;
  ppEnum               : IEnumWbemClassObject;
  apObjects            : IWbemClassObject;
  puReturned           : ULONG;
  pVal                 : Variant;
  pType                : PCIMTYPE;
  plFlavor             : PInteger;
  OpResult             : HRESULT;
  LocalConnection      : Boolean;
  AuthInfo             : TCOAUTHIDENTITY;
begin
  ZeroMemory(@AuthInfo, 0);
  with AuthInfo do
  begin
    User           := PChar(WbemUser);
    UserLength     := Length(WbemUser);
    Domain         := '';
    DomainLength   := 0;
    Password       := PChar(WbemPassword);
    PasswordLength := Length(WbemPassword);
    Flags          := SEC_WINNT_AUTH_IDENTITY_UNICODE;
  end;

  LocalConnection:=WbemComputer.IsEmpty or (WbemComputer.CompareTo('localhost')=0);
  if LocalConnection then
   if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE, nil)) then Exit
   else
  else
   if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IDENTIFY, nil, EOAC_NONE, nil)) then Exit;


  OpResult:=CoCreateInstance(CLSID_WbemLocator, nil, CLSCTX_INPROC_SERVER, IID_IWbemLocator, LWbemLocator);
  if Succeeded(OpResult) then
  begin
    try
      Writeln('Connecting to the WMI Service');
      if LocalConnection then
        OpResult:=LWbemLocator.ConnectServer(Format('\\%s\root\CIMV2',[WbemComputer]), WbemUser, WbemPassword, WbemLocale,  WBEM_FLAG_CONNECT_USE_MAX_WAIT, '', nil, LWbemServices)
      else
        OpResult:=LWbemLocator.ConnectServer(Format('\\%s\root\CIMV2',[WbemComputer]), WbemUser, WbemPassword, WbemLocale,  WBEM_FLAG_CONNECT_USE_MAX_WAIT, '', nil, LWbemServices);


      if Succeeded(OpResult) then
      begin
        Writeln('Connected');
        try
          // Set security levels on a WMI connection
          if LocalConnection then
            if Failed(CoSetProxyBlanket(LWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nil, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE)) then Exit
             else
          else
            if Failed(CoSetProxyBlanket(LWbemServices, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, PWideChar(Format('\\%s',[WbemComputer])), RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, @AuthInfo, EOAC_NONE)) then Exit;

          if Succeeded(CoCreateInstance(CLSID_UnsecuredApartment, nil, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, LUnsecuredApartment)) then
          try
            Writeln('Running Wmi Query');
            OpResult := LWbemServices.ExecQuery('WQL', 'SELECT Name, ProcessId FROM Win32_Process', WBEM_FLAG_FORWARD_ONLY, nil, ppEnum);
            if Succeeded(OpResult) then
            begin
               // Set security for the enumerator proxy
               if not LocalConnection then
                if Failed(CoSetProxyBlanket(ppEnum, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, PWideChar(Format('\\%s',[WbemComputer])), RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, @AuthInfo, EOAC_NONE)) then Exit;

               while (ppEnum.Next(Integer(WBEM_INFINITE), 1, apObjects, puReturned)=0) do
               begin
                 pType:=nil;
                 plFlavor:=nil;

                 apObjects.Get('Name', 0, pVal, pType, plFlavor);// String
                 Writeln(Format('Name         %s',[String(pVal)]));//String
                 VarClear(pVal);

                 apObjects.Get('ProcessId', 0, pVal, pType, plFlavor);// Uint32
                 Writeln(Format('ProcessId    %d',[Integer(pVal)]));//Uint32
                 VarClear(pVal);
               end;
            end
            else
            if not GetExtendedErrorInfo(OpResult) then
            Writeln(Format('Error executing WQL sentence %x',[OpResult]));
          finally
            LUnsecuredApartment := nil;
          end;
        finally
          LWbemServices := nil;
        end;
      end
      else
        if not GetExtendedErrorInfo(OpResult) then
        Writeln(Format('Error Connecting to the Server %x',[OpResult]));
    finally
      LWbemLocator := nil;
    end;
  end
  else
   if not GetExtendedErrorInfo(OpResult) then
     Writeln(Format('Failed to create IWbemLocator object %x',[OpResult]));

end;


begin
 try
    if Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED)) then
    try
      TestWbem;
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.


4 Comments

How obtain the source of the WMI Data

We normally use the WMI to either return information about software and hardware installed, but you probably ever wondered from where this data is obtained?. Well the answer is, this data is obtained from many sources like the WinApi, the Windows Registry, the SMBIOS or custom functions embedded inside of the MOF definition.

WMI Metadata

All the WMI classes have a very rich set of metadata which defines the properties names, data types, descriptions and also each class and property have a special type of attribute called qualifiers which contain addtional metadata information about the WMI element ,within these qualifiers there is one called MappingStrings.

The MSDN documentation about this qualifier states

MappingStrings : Set of values that indicate a path to a location where you can find more information about the origin of a property, class, association, indication, or reference. The mapping string can be a directory path, a URL, a registry key, an include file, reference to a CIM class, or some other format.

This means that by analyzing the content of the MappingStrings qualifier you can determine the source of the data or obtain extra information about this property. Let me explain with a sample. The Win32_DiskDrive WMI class provides information about the physical disks present in the system like Bytes Per Sector, Firmware Revision, Interface Type (SCSI, IDE, USB) and so on. Now if you analize the MappingStrings qualifier of these properties you can determine where is located the information of the disks in the system.

The Code

Check the next function to access the MappingStrings qualifier (if exist) from any WMI class.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

procedure  GetWmiPropsSources(Const NameSpace, ClassName: string);
const
  wbemFlagUseAmendedQualifiers = $00020000;
Var
  Properties        : OleVariant;
  Qualifiers        : OleVariant;
  rgvarProp         : OleVariant;
  rgvarQualif       : OleVariant;
  objSWbemLocator   : OleVariant;
  objSWbemObjectSet : OleVariant;
  objWMIService     : OleVariant;
  EnumProps         : IEnumVariant;
  EnumQualif        : IEnumVariant;
  pceltFetched      : Cardinal;
  Lindex            : Integer;
begin
    //create the WMI Scripting object
    objSWbemLocator  := CreateOleObject('WbemScripting.SWbemLocator');
    //connect to the WMi service on the local mahicne
    objWMIService    := objSWbemLocator.ConnectServer('localhost', NameSpace, '', '');
    //get the metadata of the WMI class
    objSWbemObjectSet:= objWMIService.Get(ClassName, wbemFlagUseAmendedQualifiers);
    //get a pointer to the properties
    Properties := objSWbemObjectSet.Properties_;
    //get an enumerator to the properties
    EnumProps         := IUnknown(Properties._NewEnum) as IEnumVariant;
    //iterate over the properties
    while EnumProps.Next(1, rgvarProp, pceltFetched) = 0 do
    begin
      //get a pointer to the qualifiers of the current property
      Qualifiers      := rgvarProp.Qualifiers_;
      //get an enumerator to the qualifiers
      EnumQualif     := IUnknown(Qualifiers._NewEnum) as IEnumVariant;
      //iterate over the qualifiers
      while EnumQualif.Next(1, rgvarQualif, pceltFetched) = 0 do
      begin
        //check the name of the qualifier
        if SameText('MappingStrings',rgvarQualif.Name) then
        begin
           Writeln(rgvarProp.Name);
           //write the value of the qualifier
           if not VarIsNull(rgvarQualif.Value) and  VarIsArray(rgvarQualif.Value) then
            for Lindex := VarArrayLowBound(rgvarQualif.Value, 1) to VarArrayHighBound(rgvarQualif.Value, 1) do
              Writeln(Format('  %s',[String(rgvarQualif.Value[Lindex])]));
        end;
        rgvarQualif:=Unassigned;
      end;
      rgvarProp:=Unassigned;
    end;
end;


begin
 try
    CoInitialize(nil);
    try
      GetWmiPropsSources('root\cimv2', 'Win32_DiskDrive');
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

After of execute the above code you will get a result like this

Availability
  MIF.DMTF|Operational State|003.5
  MIB.IETF|HOST-RESOURCES-MIB.hrDeviceStatus
BytesPerSector
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|BytesPerSector
Capabilities
  MIF.DMTF|Storage Devices|001.9
  MIF.DMTF|Storage Devices|001.11
  MIF.DMTF|Storage Devices|001.12
  MIF.DMTF|Disks|003.7
DeviceID
  WMI
FirmwareRevision
  Win32API|Device Input and Output Structures|STORAGE_DEVICE_DESCRIPTOR|ProductRevisionOffset
Index
  Win32API|Windows 95/98 Functions|DRIVE_MAP_INFObtInt13Unit
InstallDate
  MIF.DMTF|ComponentID|001.5
InterfaceType
  Win32API|Device Input and Output Functions|DeviceIoControl
Manufacturer
  Win32Registry|HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port\Scsi Bus\Target Id\Logical Unit
 Id\Identifier
  Win32Registry|Manufacturer
MaxMediaSize
  MIF.DMTF|Sequential Access Devices|001.2
MediaLoaded
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|MediaType|FixedMedia
MediaType
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|MediaType
Model
  Win32Registry|HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port\Scsi Bus\Target Id\Logical Unit
 Id\Identifier
  Win32Registry|ProductId
Partitions
  Win32API|Device Input and Output Structures|PARTITION_INFORMATION|RecognizedPartition
SCSIBus
  Win32API|Device Input and Output Structures|SCSI_ADDRESS|PathId
SCSILogicalUnit
  Win32API|Device Input and Output Structures|SCSI_ADDRESS|Lun
SCSIPort
  Win32API|Device Input and Output Structures|SCSI_ADDRESS|PortNumber
SCSITargetId
  Win32API|Device Input and Output Structures|SCSI_ADDRESS|TargetId
SectorsPerTrack
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|SectorsPerTrack
SerialNumber
  Win32API|Device Input and Output Structures|STORAGE_DEVICE_DESCRIPTOR|SerialNumberOffset
Signature
  Win32API|Device Input and Output Structures|DRIVE_LAYOUT_INFORMATION|Signature
Size
  Win32API|Device Input and Output Structures|DISK_GEOMETRY
StatusInfo
  MIF.DMTF|Operational State|003.3
TotalCylinders
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|Cylinders
TotalHeads
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|TracksPerCylinder
TotalSectors
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|SectorsPerTrack
TotalTracks
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|TracksPerCylinder
TracksPerCylinder
  Win32API|Device Input and Output Structures|DISK_GEOMETRY|TracksPerCylinder

As you can see most of the properties of this class have a MappingStrings qualifier which shows the source (Win32API, Win32Registry, MIF.DMTF) of the data.

Finally if you are interested on this topic take a look to the WMI Delphi Code Creator which includes this feature.


3 Comments

Determine Genuine Windows Installation using Delphi

Starting with Windows Vista , Microsoft introduces the The Software Licensing API (SLAPI), this API can be used to determine a genuine Microsoft Windows installation.

So using the SLIsGenuineLocal function you can check if your app is running in a genuine Windows installation.

This is the definition of the function

HRESULT WINAPI SLIsGenuineLocal(
  __in         const SLID *pAppId,
  __out        SL_GENUINE_STATE *pGenuineState,
  __inout_opt  SL_NONGENUINE_UI_OPTIONS *pUIOptions
);

The use of this funtion is very easy, only you must pass the GUID (Application Id) of Windows {55c92734-d682-4d71-983e-d6ec3f16059f} and a variable of type SL_GENUINE_STATE to receive the status of the license.

Check this delphi implementation

{$APPTYPE CONSOLE}
uses
  Windows,
  SysUtils;

type
  SLID  = TGUID;
  _SL_GENUINE_STATE = (
    SL_GEN_STATE_IS_GENUINE        = 0,
    SL_GEN_STATE_INVALID_LICENSE   = 1,
    SL_GEN_STATE_TAMPERED          = 2,
    SL_GEN_STATE_LAST              = 3
  );
  SL_GENUINE_STATE = _SL_GENUINE_STATE;

function SLIsGenuineLocal(var pAppId: SLID; var pGenuineState: SL_GENUINE_STATE; pUIOptions: Pointer): HRESULT; stdcall; external 'Slwga.dll' name 'SLIsGenuineLocal' delayed;

Var
  pAppId : SLID;
  pGenuineState: SL_GENUINE_STATE;
  Status: HRESULT;
begin
  try
    if Win32MajorVersion>= 6 then //Windows Vista o newer
    begin
      pAppId:=StringToGUID('{55C92734-D682-4D71-983E-D6EC3F16059F}');
      Status:=SLIsGenuineLocal(pAppId, pGenuineState,nil);
      if Succeeded(Status) then
        case pGenuineState of
            SL_GEN_STATE_IS_GENUINE       : Writeln('The installation is genuine.');
            SL_GEN_STATE_INVALID_LICENSE  : Writeln('The application does not have a valid license.');
            SL_GEN_STATE_TAMPERED         : Writeln('The Tampered flag of the license associated with the application is set.');
            SL_GEN_STATE_LAST             : Writeln('The state of the installation has not changed since the last time it was checked.');
        end
      else
        Writeln(SysErrorMessage(Cardinal(Status)));
    end
    else
        Writeln('OS not supported');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

In windows XP does not exist the SLAPI, but you can use the Win32_WindowsProductActivation WMI class to get simmilar information. the key is check the ActivationRequired property, If return 1 then the system activation is pending for the system. else If returns 0 (zero) the activation is not required.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

procedure  GetWin32_WindowsProductActivationInfo;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;

  if (Win32MajorVersion=5) and (Win32MinorVersion=1) then
  begin
    NullStrictConvert :=False;
    FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
    FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
    FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_WindowsProductActivation','WQL',wbemFlagForwardOnly);
    oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
    while oEnum.Next(1, FWbemObject, iValue) = 0 do
    begin
      Writeln(Format('Windows is Activated  %s',[BooltoStr(FWbemObject.ActivationRequired=0,True)]));
      Writeln(Format('ActivationRequired    %d',[Integer(FWbemObject.ActivationRequired)]));
      Writeln(Format('Description           %s',[String(FWbemObject.Description)]));
      Writeln(Format('ProductID             %s',[String(FWbemObject.ProductID)]));
      if FWbemObject.ActivationRequired=1 then
      begin
        Writeln(Format('RemainingEvaluationPeriod    %d',[Integer(FWbemObject.RemainingEvaluationPeriod)]));
        Writeln(Format('RemainingGracePeriod         %d',[Integer(FWbemObject.RemainingGracePeriod)]));
      end;
      Writeln(Format('ServerName            %s',[String(FWbemObject.ServerName)]));
      Writeln(Format('SettingID             %s',[String(FWbemObject.SettingID)]));

      Writeln;
      FWbemObject:=Unassigned;
    end;
  end
  else
  Writeln('OS not supported');
end;


begin
 try
    CoInitialize(nil);
    try
      GetWin32_WindowsProductActivationInfo;
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.


5 Comments

WMI Tasks using Delphi – Services

How do I determine which services are running and which ones are not?

Use the Win32_Service class to check the state of all of the services. The state property lets you know if a service is stopped or running.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT Name, State FROM Win32_Service','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Name     %s',[String(FWbemObject.Name)]));// String
    Writeln(Format('State    %s',[String(FWbemObject.State)]));// String
    Writeln;
    FWbemObject:=Unassigned;
  end;
end;

How do I stop Power Users from starting certain services?

Use the Win32_Service class and the ChangeStartMode method to set the StartMode property to Disabled. Disabled services cannot be started, and, by default, Power Users cannot change the start mode of a service.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Service where StartMode = "Manual"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.Change( varEmpty, varEmpty, varEmpty, varEmpty, 'Disabled');
    FWbemObject:=Unassigned;
  end;
end;

How do I start and stop services?

Use the Win32_Service class and the StopService and StartService methods.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Service where Name  = "Alerter"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
    FWbemObject.StartService();
end;

How do I change service account passwords?

Use the Win32_Service class and the Change method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Service where StartName = ".\netsvc"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
    FWbemObject.Change( varEmpty, varEmpty, varEmpty, varEmpty, varEmpty, varEmpty, varEmpty, 'password');
end;

How do I determine which services I can stop?

Use the Win32_Service class, and check the value of the AcceptStop property.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Service where AcceptStop = True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Name     %s',[String(FWbemObject.Name)]));// String
    FWbemObject:=Unassigned;
  end;
end;

How do I find the services that must be running before I can start the DHCP service?

Query for ASSOCIATORS OF the Win32_Service class named “DHCP” that are in the Win32_DependentService class and have “Dependent” in the Role property. Role means the role of the rasman service: in this case, it is antecedent to—must be started before—the dependent services.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('Associators Of {Win32_Service.Name="dhcp"} Where AssocClass=Win32_DependentService Role=Dependent','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('%s  - %s',[String(FWbemObject.Name),String(FWbemObject.DisplayName)]));// String
    FWbemObject:=Unassigned;
  end;
end;

How do I find the services that require the WMI service (Winmgmt) service to be running before they can start?

Query for ASSOCIATORS OF the Win32_Service class named “winmgmt” that are in the Win32_DependentService class and have “Antecendent” in the Role property. Role means the role of the rasman service: in this case, it is antecedent to—must be started before—the dependent services.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('Associators of {Win32_Service.Name="winmgmt"} Where AssocClass=Win32_DependentService Role=Antecedent','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('%s  - %s',[String(FWbemObject.Name),String(FWbemObject.DisplayName)]));// String
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN Entry WMI Tasks: Services


Leave a comment

WMI Tasks using Delphi – Registry

How do I read registry key values using WMI?

Use the StdRegProv class, located in root\default  (for Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0)   and root\cimv2 namespace for newers versions of Windows . You cannot get any instances of this class because the System Registry Provider is a method and event provider only. However, you can get registry data through methods such as EnumKey or EnumValue. The Win32_Registry, located in root\cimv2 namespace, gets data about the registry as a whole, such as how large it is.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('GetDWORDValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\Microsoft\Windows\CurrentVersion\BITS';
  FInParams.sValueName:='LogFileMinMemory';
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'GetDWORDValue', FInParams);
  Writeln(Format('sValue                %d',[Integer(FOutParams.uValue)]));
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));
end;

How do I create a new registry key?

Use the StdRegProv class, located in root\default namespace, and the CreateKey method.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('CreateKey').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'CreateKey', FInParams);
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));
end;

How do I create a new registry value under a key?

Use the StdRegProv class, located in the root\default namespace, and the CreateKey method. Then use one of the Set methods, depending on what registry datatype the value is, such as the SetDWORDValue. The Set methods create a value if it does not already exist. For more information, see Mapping a Registry Data Type to a WMI Data Type.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('SetExpandedStringValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FInParams.sValueName :='Example_Expanded_String_Value';
  FInParams.sValue     :='%PATHEXT%';
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'SetExpandedStringValue', FInParams);
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));
end;

How do I check security on a specific registry key?

Use the StdRegProv class, located in root\default namespace and the CheckAccess method. You can only check the access rights for the current user that is running the script or application. You cannot check the access rights for another specified user.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\CIMV2', User, Pass);
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('CheckAccess').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SYSTEM\CurrentControlSet';
  FInParams.uRequired:=KEY_QUERY_VALUE;
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'CheckAccess', FInParams);
  Writeln(Format('Granted     %s',[booltoStr(Boolean(FOutParams.bGranted),True)]));
  Writeln(Format('ReturnValue %d',[Integer(FOutParams.ReturnValue)]));
end;

How do I read and write binary registry values?

Use the StdRegProv class, located in root\default namespace and the GetBinaryValue and SetBinaryValue methods. Registry values that appear in the regedt32 utility as a series of byte hexadecimal values are in the REG_BINARY data format. For more information, see Mapping a Registry Data Type to a WMI Data Type. The following code example creates a new key with a binary value. The binary value is supplied in the iValues byte array specified in Hex.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
  i               : Integer;

    function ArrayToVarArray(Arr : Array Of Word):OleVariant;
    var
     i : integer;
    begin
        Result   :=VarArrayCreate([0, High(Arr)], varVariant);
        for i:=Low(Arr) to High(Arr) do
         Result[i]:=Arr[i];
    end;

begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.Get('StdRegProv');

  //Write the binary value
  FInParams     := FWbemObjectSet.Methods_.Item('SetBinaryValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FInParams.sValueName :='Example Binary Value';
  FInParams.uValue     :=ArrayToVarArray([1,2,3,4,5,6,7,8]);
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'SetBinaryValue', FInParams);
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));

  //Read the binary value
  FInParams     := FWbemObjectSet.Methods_.Item('GetBinaryValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FInParams.sValueName :='Example Binary Value';

  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'GetBinaryValue', FInParams);
   for i := VarArrayLowBound(FOutParams.uValue, 1) to VarArrayHighBound(FOutParams.uValue, 1) do
    Write(Format('%d,',[Integer(FOutParams.uValue[i])]));

  Writeln;
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));

end;

How do I read and write registry values that contain multiple strings?

Use the StdRegProv class, located in root\default namespace and the GetMultiStringValue and SetMultiStringValue methods. Registry keys that appear in the regedt32 utility as a series of strings separated by spaces are in the REG_MULTI_SZ data format. For more information, see Mapping a Registry Data Type to a WMI Data Type. The following code example creates a new key and a new multistring value.

var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
  i               : Integer;

    function ArrayToVarArray(Arr : Array Of String):OleVariant;
    var
     i : integer;
    begin
        Result   :=VarArrayCreate([0, High(Arr)], varVariant);
        for i:=Low(Arr) to High(Arr) do
         Result[i]:=Arr[i];
    end;

begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\default', '', '');
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.Get('StdRegProv');

  //Write the Multi String Value
  FInParams     := FWbemObjectSet.Methods_.Item('SetMultiStringValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FInParams.sValueName :='Example Multistring Value';
  FInParams.sValue     :=ArrayToVarArray(['String 1','String 2','String 3','String 4','String 5','String 6','String 7','String 8']);
  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'SetMultiStringValue', FInParams);
  Writeln(Format('ReturnValue %d',[Integer(FOutParams.ReturnValue)]));


  //Read the Multi String Value
  FInParams     := FWbemObjectSet.Methods_.Item('GetMultiStringValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\NewKey';
  FInParams.sValueName :='Example Multistring Value';

  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'GetMultiStringValue', FInParams);
   for i := VarArrayLowBound(FOutParams.sValue, 1) to VarArrayHighBound(FOutParams.sValue, 1) do
    Writeln(Format('%s',[String(FOutParams.sValue[i])]));

  Writeln;
  Writeln(Format('ReturnValue           %d',[Integer(FOutParams.ReturnValue)]));
end;

This article is based in the MSDN Entry WMI Tasks: Registry


Leave a comment

WMI Tasks using Delphi – Processes

How do I run an application in a hidden window?

Call the application from an app that uses the Win32_Process and Win32_ProcessStartup classes.

const
  wbemFlagForwardOnly = $00000020;
  HIDDEN_WINDOW       = 0;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
  objProcess    : OLEVariant;
  objConfig     : OLEVariant;
  ProcessID     : Integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get('Win32_ProcessStartup');
  objConfig     := FWbemObject.SpawnInstance_;
  objConfig.ShowWindow := HIDDEN_WINDOW;
  objProcess    := FWMIService.Get('Win32_Process');
  objProcess.Create('Notepad.exe', null, objConfig, ProcessID);
  Writeln(Format('Pid %d',[ProcessID]));
end;

How do I determine which scripts are running on the local computer?

Use the Win32_Process class and return all processes with the name Cscript.exe or Wscript.exe. To determine the individual scripts running in these processes, check the value of the CommandLine property.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT Name, CommandLine FROM Win32_Process Where Name="%s" or Name="%s"',['cscript.exe','wscript.exe']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Name         %s',[String(FWbemObject.Name)]));
    Writeln(Format('Command Line %s',[String(FWbemObject.CommandLine)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I find out the account name under which a process is running?

Use the Win32_Process class and the GetOwner method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  NameOfUser    : OleVariant;
  UserDomain    : OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.GetOwner(NameOfUser, UserDomain);
    Writeln(Format('Process  %s is owned by %s\%s',[String(FWbemObject.Name),String(NameOfUser), String(UserDomain)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I change the priority of a running process?

Use the Win32_Process class and the SetPriority method.

const
  wbemFlagForwardOnly = $00000020;
  ABOVE_NORMAL = 32768;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  Value         : OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process Where Name="Notepad.exe"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Value:=ABOVE_NORMAL;
    FWbemObject.SetPriority(Value);
    FWbemObject:=Unassigned;
  end;
end;

How do I terminate a process?

Use the Win32_Process class and the Terminate method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process Where Name="Notepad.exe"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.Terminate();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine how much processor time and memory each process is using?

Use the Win32_Process class and properties such as KernelModeTime, WorkingSetSize, PageFileUsage, and PageFaults.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  sngProcessTime: Double;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Process          %s',[String(FWbemObject.Name)]));
    sngProcessTime := (Int64(FWbemObject.KernelModeTime) +  Int64(FWbemObject.UserModeTime)) / 10000000.0;
    Writeln(Format('Processor Time   %n',[sngProcessTime]));
    Writeln(Format('Process Id       %d',[Integer(FWbemObject.ProcessID)]));
    Writeln(Format('Working SetSize  %d',[Int64(FWbemObject.WorkingSetSize)]));
    Writeln(Format('Page File Usage  %d',[Int64(FWbemObject.PageFileUsage)]));
    Writeln(Format('Page Faults      %d',[Int64(FWbemObject.PageFaults)]));
    FWbemObject:=Unassigned;
  end;
end;

This article is based in the MSDN entry WMI Tasks: Processes


1 Comment

WMI Tasks using Delphi – Printers and Printing

How do I add a new printer connection to a remote computer?

Use the Win32_Printer class and the AddPrinterConnection method.

var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get('Win32_Printer');
  FWbemObject.AddPrinterConnection('\\PrintServer1\ArtDepartmentPrinter');
end;

How do I set the default printer?

Use the Win32_Printer class and the SetDefaultPrinter method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM Win32_Printer Where Name = "%s"',['PrinterName']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
    FWbemObject.SetDefaultPrinter();
end;

How do I cancel print jobs using WMI?

Use the Win32_Printer class, and the CancelAllJobs method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Printer','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.CancelAllJobs();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the default printer for a computer?

Use the Win32_Printer class, and check whether the Default property is True.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Printer Where Default = True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Name    %s',[String(FWbemObject.Name)]));// String
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Printers and Printing