Mega Code Archive

 
Categories / Delphi / Forms
 

Get System information from WMI

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.