Как сделать, так что бы в ListBox можно было бы отразить процессы, происходящие в данный момент в системе и при выборе из списка специальной кнопкой их закрывать? Примерно догадываюсь, как это сделать, но как формализовать не додумаюсь? Знаю, что надо сделать снимок системы через SnapShot, подключить модуль Thelp32, а как дальше?
DRKB3 -> Системные функции и WinAPI -> Windows -> Процессы, потоки, память, задачи -> Список задач, процессы и приоритеты -> Как получить список процессов?
и
DRKB3 -> Системные функции и WinAPI -> Windows -> Запуск и завершение приложений -> Как завершить любой процесс, в том числе и системный
У меня только версия 2.3 и там есть пример просмотра и завершения процессов, но, к сожалению, только для винды 98, а, начиная с NT уже не работает. Пока нет времени, что бы скачать новую версию. Мне осталась только третья часть задания:
1. Создать список процессов. Кроме имен процессов, сохраняемых в массиве Pr_Names, необходимо сохранять в дополнительном массиве идентификаторы процессов.
2. Получить номер (индекс) выделенного мышью имени завершаемого процесса, используя метод ListBox1.ItemIndex и соответствующий ему идентификатор процесса.
3. По идентификатору процесса получить его описатель, используя функцию OpenProcess().
4. Если описатель получен, завершить процесс, используя полученный описатель.
Я написал получение списка процессов, идентификаторов процессов и базовых приоритетов потоков осталось только сделать кнопку (Button2) завершения выбранного процесса из списка, а вот как это сделать? К тому же нужно сделать, так что бы кнопка делалась активной только когда выбирается процесс из списка ListBox, это как можно сделать? Для завершения процесса используется функция TerminateProcess ( HandleProc, ExitCode). Значение описателя необходимо получить по идентификатору процесса с помощью функции OpenProcess ( PROCESS_TERMINATE)?
// Функция завершения процесса - проверено под XPВсе рабочее, проверено только что на D6 + WinXP
function ProcessTerminate(dwPID:Cardinal):Boolean;
var
hToken:THandle;
SeDebugNameValue:Int64;
tkp:TOKEN_PRIVILEGES;
ReturnLength:Cardinal;
hProcess:THandle;
begin
Result:=false;
if not OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
hToken)
then exit;
if not LookupPrivilegeValue(nil, 'SeDebugPrivilege', SeDebugNameValue) then begin
CloseHandle(hToken);
exit;
end;
tkp.PrivilegeCount:= 1;
tkp.Privileges[0].Luid := SeDebugNameValue;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken,false,tkp,SizeOf(tkp),tkp,ReturnLength);
if GetLastError()<> ERROR_SUCCESS then exit;
hProcess := OpenProcess(PROCESS_TERMINATE, FALSE, dwPID);
if hProcess = 0 then exit;
if not TerminateProcess(hProcess, DWORD(-1)) then exit;
CloseHandle( hProcess );
tkp.Privileges[0].Attributes := 0;
AdjustTokenPrivileges(hToken, FALSE, tkp, SizeOf(tkp), tkp, ReturnLength);
if GetLastError() <> ERROR_SUCCESS then exit;
Result:=true;
end;
// Немного поправляем генерацию массива строк:
procedure TForm1.Button1Click(Sender: TObject);
var
SH: Thandle;
Num, I: Integer;
PPE: TProcessEntry32;
Pr_names : array [0..50] of string;
begin
Num := 0;
SH := CreateToolHelp32SnapShot(Th32cs_SnapAll, 0);
PPE.dwSize := sizeof (ProcessEntry32);
Process32First(SH, PPE);
Pr_Names [Num] := PPE.szExeFile;
while Process32Next(SH, PPE) do begin
Num := Num + 1;
// Храним в самой строке и ProcessID
Pr_Names [Num] := '(' + inttostr(ppe.th32ProcessID) + ') ' + PPE.szExeFile;
end;
Listbox1.Clear;
for I := 0 to Num do Listbox1.Items.Add(Pr_Names[I]);
CloseHandle(SH)
end;
// Изначально button2.enabled = false
// активируется кнопка завершения процесса только при выборе
// некоторого элемента в ListBox-е
procedure TForm1.ListBox1Click(Sender: TObject);
begin
Button2.Enabled := (ListBox1.ItemIndex <> -1);
end;
// Выделяем из строки ProcessID, сообщаем и удаляем процесс...
procedure TForm1.Button2Click(Sender: TObject);
var s: string;
begin
s := ListBox1.Items[ListBox1.ItemIndex];
s := copy(s, pos('(', s) + 1, pos(')', s) - pos('(', s) - 1);
showmessage('process #' + s + ' will be destroyed');
ProcessTerminate(strtoint(s));
end;
Зачем править эту строку:
Pr_Names [Num] := '(' + inttostr(ppe.th32ProcessID) + ') ' + PPE.szExeFile;
А комментарии к function ProcessTerminate можно расписать?
P.S. Извиняюсь, скрипт [code] в этом инет-клубе не работает.
ProcessTreminate взята из DRKB 2.3 - там есть комментарии (я удалил потому, что у меня Delphi не поддерживает кириллицу...)
А как сделать, что бы после нажатия кнопки завершения процесса содержание ListBox1 обновлялось? Я пробовал дописать ListBox1.Refresh, но список не обновляется.
Добавь вызов Button1Click, чтобы заново сгенерировать список процессов.
Как реализовать, чтобы для выбранного процесса из списка ListBox’a вывести сведения о его приоритете, количестве потоков и об используемых им кучах, используя компонент StringGrid? Процесс выбирать с помощью мыши в списке из окна Listbox’а.
При помощи средств Delphi можно узнать, сколько времени процесс провел в режиме ядра и ЦП?
Вот нашел тут одну ссылку, но она на C, а как перегнать на Delphi?
NTSTATUS NtQuerySystemInformation(SystemInformationClass указывает тип информации, которую необходимо получить, SystemInformation - это указатель на результирующий буфер,
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef struct _SYSTEM_PROCESSES {
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters; // только Windows 2000
SYSTEM_THREADS Threads[1];
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
А что, собственно, там перегонять? Описания структур? В DRKB приведено несколько примеров работы с NtQuerySystemInformation, посмотри как это делается ...
С помощью NtQuerySystemInformation, можно получить вот эти сведения о приоритете и количестве потоков, об используемых кучах процессом? Я пример скачать не могу, может ссылка битая?
Посмотри вот эту тему, там Rouse_ выкладывал неплохой пример:
http://forum.sources.ru/index.php?showtopic=95006
У меня подобное задание: нужно разработать приложение для вывода всех процессов в отдельном ListBox, получения их модулей и вывода в StringGrid, при выборе процесса из ListBox1, сведений о времени старта процесса, времени работы в режиме ядра и режиме пользователя. С выводом процессов и модулей я справилась, осталось вывести сведения о времени старта процесса, времени работы в режиме ядра и режиме пользователя в StringGrid.
unit Unit1;Помогите пожалуйста разобраться.
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TlHelp32, Grids;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
Label1: TLabel;
ListBox2: TListBox;
Label2: TLabel;
StringGrid1: TStringGrid;
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
Nomp : Integer;
Pr_num : array [0..50] of integer;
SHV : Thandle;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
SH : Thandle;
Num,I : Integer;
PPE : TProcessEntry32;
Pr_names : array [0..50] of string;
begin
Num := 0;
// получение снимка состояния системы
SH := CreateToolHelp32SnapShot(Th32cs_SnapAll, 0);
// выделение из снимка имени первого процессов
PPE.dwSize := sizeof (ProcessEntry32);
Process32First(SH, PPE);
Pr_Names [Num] := PPE.szExeFile;
Pr_num [Num] := PPE.th32ProcessID;
// получение имен других процессов
while Process32Next(SH, PPE) do
begin
Num := Num + 1;
Pr_Names [Num] := PPE.szExeFile;
Pr_num [Num] := PPE.th32ProcessID;
end;
Listbox1.Clear;
// вывод списка имен выполняющихся процессов
for I := 0 to Num do
begin
Listbox1.Items.Add (Pr_Names [I] );
end;
// освобождение ресурса - снимка состояния системы
CloseHandle(SH)
end;
procedure TForm1.ListBox1Click(Sender: TObject);
type
TszModule = array [0..255] of char;
var
Num, k : integer;
Modul : TMODULEENTRY32;
Mod_name : string; // - имя модуля
begin
ListBox2.Clear;
Nomp := Pr_num [ListBox1.ItemIndex];
Label1.Caption := IntTostr(Nomp);
SHV := CreateToolHelp32Snapshot ( TH32CS_SnapMODULE, Nomp);
Modul.dwSize := sizeof (TMODULEEntry32);
Module32First(SHV, Modul);
Mod_Name :='';
for k:=0 to 255 do
begin
if Modul.szModule[k]<>#0 then
Mod_Name := Mod_Name + Modul.szModule[k]
else break;
end;
ListBox2.Items.Add(Mod_Name);
// получение имен других модулей
while Module32Next(SHV, Modul) do
begin
Mod_Name :='';
for k:=0 to 255 do
begin
if Modul.szModule[k]<>#0 then
Mod_Name := Mod_Name + Modul.szModule[k]
else break;
end;
ListBox2.Items.Add(Mod_Name);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.Cells[0,0]:='Время старта';
StringGrid1.Cells[1,0]:='UT';
StringGrid1.Cells[2,0]:='KT';
StringGrid1.Cells[0,1]:=GetProcessTimes(UserTime,TFileTime);
end;
end.
А как сделать, что бы можно было выбрать процесс из списка, а в StringGrid выводились сведения о начале его работы, завершения и приоритет?
Написал передачу параметров процессов в StringGrid? А как определить время работы процесса в режиме пользователя (UserTime) и ядра (KernelTime), а так же его время старта?
unit pro;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,TlHelp32, ComCtrls, Grids, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
ListBox1: TListBox;
ListView1: TListView;
Label2: TLabel;
Button2: TButton;
StringGrid1: TStringGrid;
Button4: TButton;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
SH : Thandle; ListBox1: TListBox;
Num, I ,a : Integer;
PPE : TProcessEntry32;
Pr_names : array [0..50] of string;
Pr_num : array [0..50] of TProcessEntry32;
Th : TTHREADENTRY32;
LstIt : TlistItem;
hToken : THandle;
DebugValue: Int64;
tkp, oldtkp : TTokenPrivileges;
Return : DWORD;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Num := 0;
// получение снимка состояния системы
SH := CreateToolHelp32SnapShot(Th32cs_SnapAll, 0);
// выделение из снимка имени первого процессов
PPE.dwSize := sizeof (ProcessEntry32);
Process32First(SH, PPE);
Pr_Names [Num] := PPE.szExeFile;
Pr_num [Num]:=PPE;
// получение имен других процессов
while Process32Next(SH, PPE) do
begin
Num := Num + 1;
Pr_Names [Num] := PPE.szExeFile; Pr_num [Num]:=PPE;
end;
Listbox1.Clear;
// вывод списка имен выполняющихся процессов
for I := 0 to Num do Listbox1.Items.Add(Pr_Names[I]);
// освобождение ресурса - снимка состояния системы
CloseHandle(SH);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Sh := CreateToolHelp32Snapshot (TH32CS_SNAPALL,0);
Th.dwSize := sizeof (TTHREADEntry32);
Thread32First(sh,Th);
ListView1.Items.Clear;
LstIt :=ListView1.Items.Add;
LstIt.Caption:=IntToStr(Th.th32OwnerProcessID);
LstIt.SubItems.Add(IntToStr(Th.tpBasePri));
repeat
LstIt :=ListView1.Items.Add;
LstIt.Caption:=IntToStr(Th.th32OwnerProcessID);
LstIt.SubItems.Add(IntToStr(Th.tpBasePri))
until not Thread32Next (sh,Th);
CloseHandle(Sh);
end;
procedure TForm1.ListBox1Click(Sender: TObject);
begin
StringGrid1.Cells[0,1]:=IntToStr(Pr_num[ListBox1.ItemIndex].th32ProcessID);
StringGrid1.Cells[1,1]:=IntToStr(Pr_num[ListBox1.ItemIndex].th32ModuleID);
StringGrid1.Cells[2,1]:=IntToStr(Pr_num[ListBox1.ItemIndex].cntThreads);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.Cells[0,0]:='Ид.процесса';
StringGrid1.Cells[1,0]:='Модули';
StringGrid1.Cells[2,0]:='Потоки';
StringGrid1.Cells[3,0]:='Время старта';
StringGrid1.Cells[4,0]:='UserTime';
StringGrid1.Cells[5,0]:='KernelTime';
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
Close;
end;
end.
Доделал я это задание (получить список выполняющихся процессов в системе, вывести модули выбранного процесса и его потоки, идентификатор, время старта, работы в режиме ядра и пользователя), если кому интересно, то вот код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TlHelp32, Grids;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
ListBox2: TListBox;
Label2: TLabel;
StringGrid1: TStringGrid;
Button2: TButton;
Label3: TLabel;
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
Nomp : Integer;
Pr_num : array [0..50] of integer;
SHV : Thandle;
//Pr_nam : array [0..50] of TProcessEntry32;
H:THandle;
N:integer;
Pr_nam : array [0..50] of TProcessEntry32;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
SH : Thandle;
Num,I : Integer;
PPE : TProcessEntry32;
Pr_names : array [0..50] of string; //integer
begin
Num := 0;
// получение снимка состояния системы
SH := CreateToolHelp32SnapShot(Th32cs_SnapAll, 0);
// выделение из снимка имени первого процессов
PPE.dwSize := sizeof (ProcessEntry32);
Process32First(SH, PPE);
Pr_Names [Num] := PPE.szExeFile; //cntThreads;
Pr_num [Num] := PPE.th32ProcessID;
Pr_nam[Num]:=PPE;
// получение имен других процессов
while Process32Next(SH, PPE) do
begin
Num := Num + 1;
Pr_Names [Num] := PPE.szExeFile; //cntThreads;
Pr_num [Num] := PPE.th32ProcessID;
Pr_nam[Num]:=PPE;
end;
Listbox1.Clear;
// вывод списка имен выполняющихся процессов
for I := 0 to Num do
begin
Listbox1.Items.Add (Pr_Names [I]); //(inttostr(Pr_Names [I] ));
end;
// освобождение ресурса - снимка состояния системы
CloseHandle(SH)
end;
procedure TForm1.ListBox1Click(Sender: TObject);
type
TszModule = array [0..255] of char;
var
Num, k : integer;
Modul : TMODULEENTRY32;
Mod_name : string; // - имя модуля
//Pr_nam : array [0..50] of TProcessEntry32;
start,ex,KT,UT,LFT:TFileTime;
ST:TSystemTime;
q:THandle;
begin
ListBox2.Clear;
Nomp := Pr_num [ListBox1.ItemIndex];
//Label1.Caption := IntTostr(Nomp);
SHV := CreateToolHelp32Snapshot ( TH32CS_SnapMODULE, Nomp);
Modul.dwSize := sizeof (TMODULEEntry32);
Module32First(SHV, Modul);
Mod_Name :='';
for k:=0 to 255 do
begin
if Modul.szModule[k]<>#0 then
Mod_Name := Mod_Name + Modul.szModule[k]
else break;
end;
ListBox2.Items.Add(Mod_Name);
// получение имен других модулей
while Module32Next(SHV, Modul) do
begin
Mod_Name :='';
for k:=0 to 255 do
begin
if Modul.szModule[k]<>#0 then
Mod_Name := Mod_Name + Modul.szModule[k]
else break;
end;
ListBox2.Items.Add(Mod_Name);
end;
begin
N:=Pr_num [ListBox1.ItemIndex];
q:=OpenProcess(PROCESS_QUERY_INFORMATION,true,N);
begin
GetProcessTimes(q,start,ex,KT,UT);
FileTimeToLocalFileTime(start,LFT);
FileTimeToSystemTime(LFT,ST);
StringGrid1.cells[0,1]:=IntToStr(Nomp);//(Pr_nam[ListBox1.ItemIndex].th32ProcessID);
StringGrid1.cells[1,1]:=IntToStr(Pr_nam[ListBox1.ItemIndex].cntThreads);
Form1.StringGrid1.Cells[2,1]:=IntToStr(ST.wHour)+':'+
IntToStr(ST.wMinute)+':'+IntToStr(ST.wSecond);
end;
begin
FileTimeToLocalFileTime(UT,LFT);
FileTimeToSystemTime(LFT,ST);
Form1.StringGrid1.Cells[3,1]:=IntToStr(ST.wSecond)+':'+IntToStr(ST.wMilliseconds);
end;
begin
FileTimeToLocalFileTime(KT,LFT);
FileTimeToSystemTime(LFT,ST);
Form1.StringGrid1.Cells[4,1]:=IntToStr(ST.wSecond)+':'+IntToStr(ST.wMilliseconds);
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.cells[0,0]:='Идентификатор процесса';
StringGrid1.cells[1,0]:='Потоки';
StringGrid1.cells[5,0]:='Базовый приоритет';
StringGrid1.cells[2,0]:='Время старта';
StringGrid1.cells[3,0]:='User Time';
StringGrid1.cells[4,0]:='Kernel Time';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Close;
end;
end.
Может, кто знает, как получить имя файла и его версию по имени созданного им процесса? То есть: есть список процессов (см. выше) и по клику на имени процесса выводить имя файла создавшего его и его версию?