S použitím WMI dnes budeme zkoumat běžící procesy a zjišťovat o nich velmi detailní informace.
Co je to vlastně WMI? Je to zkratka z Windows Management Instrumentation a detailnější popis by si vyžádal dost času. Velmi zjednodušeně řečeno (odborníci prominou) je to jedna z komponent systému Windows, která zpřístupňuje informace o systému, aplikacích, síti, zařízeních a podobně. Detailnější informace najdete jako obvykle na MSDN.
Toto rozhraní vám umožní zvládnout rozličné úkoly a zjistit řadu informací. O co všechno se jedná a jak na to naleznete opět zde na MSDN. Je určeno pro použití v C/C++, Visual Basicu, ale i s pomocí ActiveX (to bude náš případ).
Náš dnešní program tedy bude zjišťovat informace o běžících procesech a vypisovat tyto údaje do Mema. Prvním krokem bude importování příslušné knihovny do Delphi. V menu Project vybereme volbu Import Type Library. V zobrazeném okně pak prolistujeme seznam a najdeme položku Microsoft WMI Scripting Library (na disku by se měl soubor nacházet ve složce {Windows}\System32\wbem\wbemdisp.TLB). Klikneme na Install a na záložce ActiveX pak nalezneme několik nových komponent.
Ty nás ovšem nebudou zajímat, pro nás je teď podstatné pouze to, že máme knihovnu v Delphi nainstalovanou a pouze přidáme do uses hlavního formuláře jednotku WbemScripting_TLB a také ActiveX. Na formulář pak ještě přidáme tlačítko, kterým budeme spouštět celou akci, a zmiňované Memo, kam se budou informace vypisovat.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ActiveX, WbemScripting_TLB, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function ADsEnumerateNext(pEnumVariant: IEnumVARIANT; cElements: ULONG; var pvar: OleVARIANT; var pcElementsFetched: ULONG): HRESULT; safecall; external `activeds.dll`;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure DumpWMI_Process(Process: SWBemObject);
var
Enum: IEnumVARIANT;
varArr: OleVariant;
lNumElements: ULong;
SProp: ISWbemProperty;
Prop: OleVariant;
PropName: string;
PropType: string;
PropValue: string;
begin
Form1.Memo1.Lines.Add(`+ WMI Path: ` + Process.Path_.Path);
Enum := Process.Properties_._NewEnum as IEnumVariant;
while (Succeeded(ADsEnumerateNext(Enum, 1, VarArr, lNumElements))) and (lNumElements > 0) do
if Succeeded(IDispatch(varArr).QueryInterface(SWBemProperty, SProp)) and Assigned(SProp) then
try
PropName := SProp.Name;
Prop := SProp.Get_Value;
PropType := VarTypeAsText(VarType(Prop));
PropValue := VarToStr(Prop);
Form1.Memo1.Lines.Add(` + ` + PropName + `[` + PropType + `] = ` + PropValue);
except
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Server: string;
Enum: IEnumVARIANT;
varArr: OleVariant;
lNumElements: ULong;
AName: array[0..255] of Char;
ASize: DWORD;
begin
if (ParamCount = 0) then
begin
Server := ``;
ASize := SizeOf(AName) - 1;
if GetComputerName(@AName, ASize) then Server := AName;
end
else Server := ParamStr(1);
try
Memo1.Lines.BeginUpdate;
Enum := CoSWbemLocator.Create.ConnectServer(Server, `root\cimv2`, ``, ``, ``, ``, 0, nil).ExecQuery(`Select * from Win32_Process`, `WQL`, wbemFlagBidirectional, nil)._NewEnum as IEnumVariant;
while (Succeeded(ADsEnumerateNext(Enum, 1, varArr, lNumElements))) and (lNumElements > 0) do
begin
DumpWMI_Process(IUnknown(varArr) as SWBemObject);
Memo1.Lines.Add(``);
end;
finally
Memo1.Lines.EndUpdate;
end;
end;
end.
A jaké informace vlastně získáme? Kromě obvyklých věcí jako je název procesu, řetězec příkazové řádky či případně cesta k souboru je to ohromné množství čísel. Čas vytvoření procesu, jeho priorita, množství číselných údajů o použité paměti a podobně. Celkem je to asi 46 údajů, takže je to popis opravdu velmi detailní. Memo je zde použito pro zjednodušení, jinak to samozřejmě není příliš vhodná komponenta pro zobrazení podobných údajů a lepší by asi byla tabulka, resp. ListView. Příslušná úprava procedury DumpWMI_Process ale již jistě nebude velkým problémem.