Forms Delphi

Title: Get System information from WMI
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 := ''
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 := '';
wbemCimtypeObject:
ValueName := '';
else
ValueName := '';
end; {case}
keyname := String(SProp.Name);
Result := ValueName;
end;
end.