Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Get System information from WMI

System Information

Get System information from WMI

by  Glenn9999  Posted    (Edited  )
Most Windows computers these days have something on them called WMI or Windows Management Instrumentation. You can do a number of things on the local computer or even the remote computer using WMI. Even more so, this is the recommended standard Microsoft way to do things and it is ever more so when it comes to Vista and Windows 7. This FAQ will describe how to get information. Also within WMI, there are numerous methods which will do different things. How to do that will not be focused upon in this FAQ.

WMI (in most cases I've seen) is arranged in the form of object tables, whose data are accessed in a subset of SQL that Microsoft calls WQL. What is allowed and not allowed, along with these table definitions are in the MSDN reference for WMI (http://msdn.microsoft.com/en-us/library/aa394582(VS.85).aspx). Needless to say there is a great number of them, and you can find out just about anything regarding your local system or any system on the network that you can connect to like the running hardware stats, along with memory usages, processes, and threads.

Beware, that selecting all the data in some of the tables will take a very large time and a huge amount of resources, so be careful to limit your statements as you would in dealing with a regular database.

Most of what is involved in getting information involves connecting through the interface, preparing and submitting a WQL statement, and then parsing through and displaying the results. To do this, Microsoft provides ActiveX interfaces for this purpose.

The first step to gain use of these interfaces is to Import the Type library for the WMI interfaces. To do this, bring up the option for this in the Delphi you are using (the process varies so I won't describe it here), and select " Microsoft WMI Scripting V1.2 Library".

I've encapsulated much of the WMI processes in wmiserv.pas posted below, to ease the process somewhat. The main example will show how to obtain the command-lines of all running processes (this is the "more supported" way to do what was posted in http://www.tek-tips.com/viewthread.cfm?qid=1568667).

While I select three fields out of the table in question, note that WMI always returns the primary key of the table whether you ask for it or not. I am selecting the primary key of Win32_Process (handle) in doing this call, so it is not an issue. However, it shouldn't be anyway if you use the method described below.

Main unit for the sample program.
Code:
unit pwmiunit;
// process command-line viewer for the local machine using WMI written by Glenn9999 at tek-tips.com.
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ActiveX, wmiserv, WbemScripting_TLB, ComCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
{ this is a WMI reporting example where you know the fields you want. }
var
  NewColumn: TListColumn;
  ListItem: TListItem;

  WbemLocator: SWbemLocator;
  WbemServices: ISWbemServices;
  ObjectSet:  ISWbemObjectSet;
  outstmt: string;
  RowENum: IEnumVariant;
  tempObj: OleVariant;
  SProp: OleVariant;
  keyname: string;
begin
  WBemLocator := WMIStart;
  WBemServices := WMIConnect(WBemLocator, '', '', '');
  ObjectSet := WMIExecQuery(WbemServices,
               'select handle, caption, CommandLine from Win32_Process');

  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;
  ListView1.Items.Clear;
  ListView1.ViewStyle := vsReport;
  NewColumn := ListView1.Columns.Add;
  NewColumn.Caption := 'Handle';
  NewColumn.Width := -2;
  NewColumn := ListView1.Columns.Add;
  NewColumn.Caption := 'Caption';
  NewColumn.Width := -2;
  NewColumn := ListView1.Columns.Add;
  NewColumn.Caption := 'Command Line';
  NewColumn.Width := -2;

  WMIRowFindFirst(ObjectSet, RowENum, tempobj);
  repeat
    SProp := tempobj.Properties_.Item('handle', 0);
    outstmt := WMIConvValue(SProp, keyname);
    ListItem := ListView1.Items.Add;
    ListItem.Caption := outstmt;

    SProp := tempobj.Properties_.Item('caption', 0);
    outstmt := WMIConvValue(SProp, keyname);
    ListItem.SubItems.Add(outstmt);

    SProp := tempobj.Properties_.Item('CommandLine', 0);
    outstmt := WMIConvValue(SProp, keyname);
    ListItem.SubItems.Add(outstmt);
  until WMIRowFindNext(RowENum, tempobj) = false;
  ListView1.Items.EndUpdate;
end;

end.

WMISERV.PAS
Code:
unit wmiserv;
// WMI service sample written by Glenn9999 at tek-tips.com
interface
  uses comobj, activex, WbemScripting_TLB;

  const
    EOAC_NONE = 0;
    RPC_C_AUTHN_WINNT = 10;
    RPC_C_AUTHZ_NONE = 0;
    RPC_E_CHANGED_MODE = -2147417850;

function WMIStart: ISWBemLocator;
function WMIConnect(WBemLocator: ISWBemLocator; Server, account, password: string): ISWBemServices;
function WMIExecQuery(WBemServices: ISWBemServices; query: string): ISWbemObjectSet;
function WMIRowFindFirst(ObjectSet: ISWbemObjectSet; var ENum: IEnumVariant; var tempobj: OleVariant): boolean;
function WMIRowFindNext(ENum: IENumVariant; var tempobj: OleVariant): boolean;
function WMIColFindFirst(var propENum: IENumVariant; var tempObj: OleVariant): boolean;
function WMIColFindNext(propENum: IENumVariant; var tempobj: OleVariant): boolean;
function WMIGetValue(wbemservices: ISWBemServices; tablename, fieldname: string): string;
function WMIConvValue(tempobj: OleVariant; var keyname: string): string;

implementation
  uses sysutils;

function WMIStart: ISWBemLocator;
  // creates the WMI instance along with any error checking
  var
    HRes: HResult;
  begin
    Result := nil;
    HRes := CoCreateInstance(Class_SWbemLocator, nil, CLSCTX_INPROC_SERVER,
              ISWbemLocator, Result);
    if HRes <> 0 then
      raise EOleException.Create('Locator instance not created.', 1, '', '', 0);
  end;

function WMIConnect(WBemLocator: ISWBemLocator; Server, account, password: string): ISWBemServices;
 // connects to a machine for WMI usage.
  begin
    Result := nil;
    try
      Result := WBEMLocator.ConnectServer(Server, 'root\CIMV2', '', Account,
               Password, '', 0, nil);
    except
      on EOleException do
        raise EOleException.Create('incorrect credentials.  WMI connection failed.', 1, '', '', 0);
    end;
    CoSetProxyBlanket(Result, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
             nil,
             wbemAuthenticationLevelCall, wbemImpersonationLevelImpersonate,
             nil, EOAC_NONE);
  end;

function WMIExecQuery(WBemServices: ISWBemServices; query: string): ISWbemObjectSet;
  // executes a WQL query.
  begin
    Result := nil;
    try
      Result := WBEmServices.ExecQuery(query, 'WQL',
             wbemFlagReturnImmediately,
             nil);
    except
      on EOleException do
        raise EOleException.Create('Invalid statement.  Please resubmit.', 1, '', '', 0);
    end;
  end;

function WMIRowFindFirst(ObjectSet: ISWbemObjectSet; var ENum: IEnumVariant; var tempobj: OleVariant): boolean;
// finds the first row in a result set.
  var
    Value: Longint;
  begin
    Enum :=  (ObjectSet._NewEnum) as IEnumVariant;
    Result := (ENum.Next(1, tempObj, @Value) = 0);
  end;

function WMIRowFindNext(ENum: IENumVariant; var tempobj: OleVariant): boolean;
// finds the next row in a result set.
  var
    Value: Longint;
  begin
    Result := (ENum.Next(1, tempObj, @Value) = 0);
  end;

function WMIColFindFirst(var propENum: IENumVariant; var tempObj: OleVariant): boolean;
 // finds the first column in a row.
  var
    Value: Longint;
    propSet: ISWBemPropertySet;
    SObject: ISWbemObject;
  begin
    SObject := IUnknown(tempObj) as ISWBemObject;
    propSet := SObject.Properties_;

    propEnum := (propSet._NewEnum) as IEnumVariant;
    Result := (propEnum.Next(1, tempObj, @Value) = 0);
  end;

function WMIColFindNext(propENum: IENumVariant; var tempobj: OleVariant): boolean;
  // finds the next column in a row.
  var
    Value: Longint;
  begin
    Result := (propENum.Next(1, tempObj, @Value) = 0);
  end;

function WMIGetValue(wbemservices: ISWBemServices; tablename, fieldname: string): string;
  { this will return the value of the first fieldname that occurs in tablename }
  var
    statement: string;
    RowENum: IENumVariant;
    ObjectSet:  ISWbemObjectSet;
    tempobj: OleVariant;
    SObject: ISWbemObject;
    Sprop: ISWBemProperty;
  begin
    Result := '';
    statement := 'SELECT ' + fieldname + ' FROM ' + tablename;
    ObjectSet := WMIExecQuery(WbemServices, statement);
    if WMIRowFindFirst(ObjectSet, RowENum, tempobj) then
      begin
        SObject := IUnknown(tempObj) as ISWBemObject;
        SProp := SObject.Properties_.Item(fieldname, 0); // specific field property
        Result := WMIConvValue(SProp, fieldname);
      end;
  end;

function WMIConvValue(tempobj: OleVariant; var keyname: string): string;
  { generic WMI value to string conversion of "valuename".
    Returns the field name into "keyname".  Adapted from Denis Blondeau 's SWBEM example. }
  var
    Count: Longint;
    SProp: ISWbemProperty;
    valuename: string;
  begin
    SProp := IUnknown(tempObj) as ISWBemProperty;
    ValueName := '';
    if VarIsNull(SProp.Get_Value) then
      ValueName := '<empty>'
    else
      case SProp.CIMType of
         wbemCimtypeSint8, wbemCimtypeUint8, wbemCimtypeSint16, wbemCimtypeUint16,
         wbemCimtypeSint32, wbemCimtypeUint32, wbemCimtypeSint64:
           if VarIsArray(SProp.Get_Value) then
              begin
                if VarArrayHighBound(SProp.Get_Value, 1) > 0 then
                  for Count := 1 to VarArrayHighBound(SProp.Get_Value, 1) do
                    ValueName := ValueName + ' ' + IntToStr(SProp.Get_Value[Count]);
              end
           else
             ValueName := IntToStr(SProp.Get_Value);
         wbemCimtypeReal32, wbemCimtypeReal64:
           ValueName := FloatToStr(SProp.Get_Value);
         wbemCimtypeBoolean:
           if SProp.Get_Value then
             ValueName := 'True'
           else
             ValueName := 'False';
         wbemCimtypeString, wbemCimtypeUint64:
           if VarIsArray(SProp.Get_Value) then
              begin
                if VarArrayHighBound(SProp.Get_Value, 1) > 0 then
                  for Count := 1 to VarArrayHighBound(SProp.Get_Value, 1) do
                    ValueName := ValueName + ' ' + SProp.Get_Value[Count];
              end
           else
              ValueName :=  SProp.Get_Value;
         wbemCimtypeDatetime:
           ValueName :=  SProp.Get_Value;
         wbemCimtypeReference:
           ValueName := SProp.Get_Value;
         wbemCimtypeChar16:
           ValueName := '<16-bit character>';
         wbemCimtypeObject:
           ValueName := '<CIM Object>';
      else
        ValueName := '<Unknown type>';
      end; {case}
      keyname := String(SProp.Name);
      Result := ValueName;
end;


end.
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top