Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 139. - zkoumání běžících procesů

Jan Šindelář - 19.5.2004

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.