Unit SelectProcessForm;

{
  Formular slouzici pro vyber jednoho ze seznamu bezicich procesu.
  O vybranem procesu vrati volajicimu nasledujici informace:
  * PID
  * Jmeno hlavniho souboru
}

Interface

uses
  Windows, Messages, SysUtils, Variants, Classes,
  Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls;

Type
  // Kriteria, podkle kterych je mozne seznam procesu seradit
  TProcessListOrder = (ploPID, ploName, ploPriority, ploThreads);
  // Vzestupne/sestupne razeni
  TProcessListDirection = (pldAscending, pldDescending);

  TSelectProcess = Class (TForm)
    Button1: TButton;
    Button2: TButton;
    Panel1: TPanel;
    Button3: TButton;
    ListView1: TListView;
    Procedure Button2Click(Sender: TObject);
    Procedure FormCreate(Sender: TObject);
    Procedure Button3Click(Sender: TObject);
    Procedure FormClose(Sender: TObject; var Action: TCloseAction);
    Procedure Button1Click(Sender: TObject);
    procedure ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
      Data: Integer; var Compare: Integer);
    procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
  Private
    FProcessName : WideString;
    FProcessId : DWORD;
    FCanceled : Boolean;
    // Aktualni kriterium razeni seznamu procesu
    FProcessListOrder : TProcessListOrder;
    // Aktualni smer razeni (vzestupny ci sestupny)
    FProcessListDirection : TProcessListDirection;
  Public
    // True - vyber byl zrusen uzivatelem, False - byl vybran nejaky proces
    Property Canceled : Boolean Read FCanceled;
    // Jmeno vybraneho procesu
    Property ProcessName : WideString Read FProcessName;
    // PID vybraneho procesu
    Property ProcessId : DWORD Read FProcessId;
  end;


Implementation

{$R *.DFM}

Uses
  Utils, TlHelp32;


Procedure TSelectProcess.Button1Click(Sender: TObject);
{
  Rutina je zavolana pri kliknuti na tlacitko "Ok". Pokud
  je nejaky proces v seznamu oznacen, rutina zjisti jmeno
  jeho souboru a PID a ulozi je do vystupnich promennych
  objektu formulare. Nasledne formular zavre.
}
Var
  L : TListItem;
begin
L := ListView1.Selected;
FCanceled := Not Assigned(L);
If Not FCanceled Then
  begin
  FProcessName := PProcessInfoRecord(L.Data).Name;
  FProcessId := PProcessInfoRecord(L.Data).PID;
  Close;
  end;
end;

Procedure TSelectProcess.Button2Click(Sender: TObject);
{
  Tato rutina je volana pri kliknuti na tlacitko "Storno".
  Jelikoz je implicitni stav vystupni promenne Canceled nastaven
  na True, pouze zavre formular.
}
begin
Close;
end;

Procedure TSelectProcess.Button3Click(Sender: TObject);
{
  Obnovi seznam procesu. Tato operace se provadi v nekolika krocich
  1) Odstraneni vsech polozek prvku ListView (kazda reprezentuje
     jeden proces) a vuolneni pameti s nimi spjate.
  2) Ziskani seznamu bezicich procesu. Informace o jednotlivych procesech
     jsou ulozeny ve forme TProcessInfORecord zaznamu.
  3) Vytvoreni jedne polozky v ListViewu pro kazdy proces. Tato polozka
     je asociovana s konkretnim TProcessInfoRecord zaznamem.
  4) Zruseni seznamu, ktery spojovel zaznami TProcessInfORecord, ktere
     jsou nyni navazany na jednotlive polozky prvku ListView.
  5) Serazeni polozek v ovladacim prvku Listview podle  aktualne
     zvoleneho kriteria a smeru (ulozeno v polozkach FProcessListOrder
     a FProcessListDirection v objektu formulare).
}
Var
  I : Integer;
  Item : TListItem;
  ProcessList : TList;
  PIR : PProcessInfoRecord;
begin
ListView1.Items.BeginUpdate;
ListView1.Items.Clear;
For I := 0 To ListView1.Items.Count - 1 Do
  begin
  PProcessInfoRecord(ListView1.Items[I].Data).Name := '';
  MemFree(ListView1.Items[I].Data);
  end;

ProcessList := TList.Create;
If GetProcessList(ProcessList) Then
  begin
  // Zapis informaci o jednotlivych bezicich
  // procesech do ovladaciho prvku ListView
  For I := 0 To ProcessList.Count - 1 Do
    begin
    PIR := PProcessInfoRecord(ProcessList[I]);
    Item := ListView1.Items.Add;
    Item.Data := PIR;
    Item.Caption := IntToStr(PIR.PID);
    Item.SubItems.Add(PIR.Name);
    Item.SubItems.Add(IntToStr(PIR.Priority));
    Item.SubItems.Add(IntToStr(PIR.NumberOfThreads));
    end;
  end
Else begin
  // Pri zjistovani procesu doslo k chybe. V seznamu
  // jiz mohou byt nejake, ale neuplne informace.
  // Odstranime je z pameti.
  For I := 0 To ProcessList.Count - 1 Do
    begin
    PProcessInfoRecord(ProcessList[I]).Name := '';
    MemFree(ProcessList[I]);
    end;

  Error('Nepodarilo se ziskat seznam procesu');
  end;

ProcessList.Free;
ListView1.AlphaSort;
ListView1.Items.EndUpdate;
end;

Procedure TSelectProcess.FormClose(Sender: TObject; var Action: TCloseAction);
{
  Rutina je volana pri zavreni formulare. Zajisti uvolneni
  vsech dat asociovanych s polozkami ovladaciho prvku ListView.
}
Var
  I : Integer;
begin
For I := 0 To Listview1.Items.Count - 1 Do
  begin
  PProcessInfoRecord(ListView1.Items[I].Data).Name := '';
  MemFree(ListView1.Items[I].Data);
  end;
end;

Procedure TSelectProcess.FormCreate(Sender: TObject);
{
  Rutina je volana tesne po vytvoreni formulare. Provede
  potrebnou inicializaci jeho atributu a necha vygenerovat
  seznam aktualne bezicich procesu.
}
begin
FCanceled := True;
FProcessListOrder := ploName;
FProcessListDirection := pldAscending;
Button3Click(Nil);
end;

Procedure TSelectProcess.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
{
  Tato rutina je volana pri kliknuti na hlavicku sloupce ovladaciho
  prvku ListVIew. Na zaklade teto udalosti meni kriterium razeni
  seznamu procesu ci jeho smer.
}
Var
  Index : Integer;
begin
Index := Column.Index;
If Ord(FProcessListOrder) = Index Then
  begin
  If FProcessListDirection = pldAscending Then
    FProcessListDirection := pldDescending
  Else FProcessListDirection := pldAscending;
  end
Else begin
  FProcessListOrder := TProcessListOrder(Index);
  FProcessListDirection := pldAscending;
  end;

ListView1.AlphaSort;
end;

Procedure TSelectProcess.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
{
  Porovnava dve polozky ovladaciho prvku ListView podle aktualne
  nastaveneho kriteria a aktualniho smeru razeni. Tuto rutinu
  ListView interne pouziva pro razeni sveho obsahu.
}
Var
  I1 : PProcessInfoRecord;
  I2 : PProcessInfoRecord;
begin
Compare := 0;
I1 := PProcessInfoRecord(Item1.Data);
I2 := PProcessInfoRecord(Item2.Data);
Case FProcessListOrder Of
  ploPID : Compare := I1.PID - I2.PID;
  ploName : Compare := StrComp(PWideChar(I1.Name), PWideChar(I2.Name));
  ploPriority : Compare := I1.Priority - I2.Priority;
  ploThreads : Compare := I1.NumberOfThreads - I2.NumberOfThreads;
  end;

If FProcessListDirection = pldDescending Then
  Compare := -Compare;
end;

End.

