Назад |
Скачай демонстрационный проект (26,1 кб)
В Windows NT почему-то не включены Tool Help API. Там имеется другая библиотека Process Status Helper. Скрывается она в файле psapi.dll и позволяет получать информацию и процессах и драйверах устройств. Для работы библиотеки в Delphi в раздел uses надо включить модуль PsAPI. Кстати, в Windows 95/98 этой библиотеки нет.
При пользовании функций этой либы часто требуется дескриптор (хэндл) процесса. Чтобы его получить надо вызвать OpenProcess с PID’ом нужного процесса в параметрах. Так как многие системные процессы не захотят открываться пользовательской проге, то присвоим ей привилегии отладчика с помощью функции EnableDebugPrivileges. (Описание ее смотри в части №0.Подготовка.) Но даже в этом случае наша функция нормально работает только под амином. Под пользователем половина процессов не открывается. То есть PID’ы-то мы получим, но информацию о них извлечь не сможем.
Для получения списка процессов служим функция EnumProcesses:
|
Если функция успешно выполнилась – она возвращает True. Нет никакой возможности точно определить сколько памяти выделять под буфер. MSDN рекомендует сразу выделить буфер побольше (в примере она выделяет 1 килобайт). Если буфер оказался слишком маленьким, то предупреждение об этом тоже не дается, а просто массив обрезается до размеров буфера. Поэтому, если cbNeeded равно размеру буфера (cb), то надо выделять буфер побольше и вызывать функцию EnumProcesses снова. Так мы и сделаем.
Количество элементов в массиве подсчитывается просто: делим количество возвращенных байт на размер PID’а (то есть на размер DWORD) и получаем количество элементов в массиве.
Дальше, обходя массив в цикле, получаем PID’ы всех процессов. Получаем для них дескрипторы через OpenProcess. И уже по дескрипторам получаем информацию о процессе. Имя исполняемого файла можно получить двумя способами.
Первый работает только в Windows XP (и наверное еще в Висте) - в библиотеку PsAPI добавлена функция GetProcessImageFileName:
|
Она возвращает путь к исполняемому файлу в несколько специфичном формате, типа -\Device\HarddiskVolume2\WINDOWS\explorer.exe У меня например -\Device\HarddiskVolume2 это диск F: (загрузочный).
Второй способ был и раньше. Функции GetModuleBaseName, GetModuleFilenameEx возвратят имя исполняемого модуля (экзешника) и полный путь к файлу этого модуля. Вторым параметром у этих функций идет хендл модуля, о котором собирается информация. Мы передадим туда просто ноль и получим инфу о главном модуле.
В этой реализации функции FillProcessesList в качестве примера будут использованы все вышеперечисленные функции:
unit Sample2;
interface
uses Classes;
function FillProcessesList(var
slProcesses: TStringList): Boolean;
implementation
uses Windows, SysUtils, PsAPI,
Addition;
// Используем ANSI версию функции
GetProcessImageFileName
function
GetProcessImageFileName(hProcess: THandle; lpFilename: PAnsiChar;
nSize: DWORD): DWORD; stdcall;
external 'psapi.dll'
name 'GetProcessImageFileNameA';
// Получаем список процессов и
заполняем им TStringList
function FillProcessesList(var
slProcesses: TStringList): Boolean;
const
INCREMENTAL_SIZE = 64; // шаг
изменения размера массива aProcessIds
var
aProcessIds: array of DWORD; //
Динамический массив для PID'ов
iSize: Cardinal; // количесво
элементов массива aProcessIds
dwBytesReturned: DWORD; //
количество байт, возвращенных EnumProcesses
iProcessesCount: Integer; //
количество PID'ов в массиве aProcessIds
i: Integer; // счетчик цикла
hProcess: THandle; // дескриптор
открытого процесса
sBaseName: array [0..MAX_PATH] of
Char; // Буферы для строк
sFileName: array [0..MAX_PATH] of
Char;
sImageFileName: array
[0..MAX_PATH] of Char;
sOut:
String;
// строка для добавления в
TStringList
begin
Result := False;
if slProcesses = nil then Exit;
// Проверяем кооректность параметра
EnableDebugPrivileges; //
Включаем отладочные привилегии
iSize := 0; // инициируем размер
массива
repeat
inc(iSize, INCREMENTAL_SIZE);
// увеличиваем размер массива
SetLength(aProcessIds,iSize);
// устанавливаем новый размер массива
if
not
EnumProcesses(@aProcessIds[0],
//заполняем массив PID'ами
iSize
* SizeOf(DWORD),
//размер массива в байтах
dwBytesReturned) then Exit;
//возращенные байты
until dwBytesReturned < (iSize *
SizeOf(DWORD)); // если буфера мало, то снова
// Считаем количество процессов в
массиве
iProcessesCount :=
dwBytesReturned div SizeOf(DWORD);
// Получаем в цикле инфу для каждого элемента
массива
for i := 0 to iProcessesCount-1 do
begin
sOut := IntToStr(i + 1) + ' -
PID: ' + IntToStr(aProcessIds[i]);
// Открываем процесс по
PID'у
с флагами для получения информации
hProcess :=
OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
False,
aProcessIds[i]);
if hProcess = 0 then
sOut
:= sOut
+ ' Не могу открыть процесс.'
else begin
if
GetModuleBaseName(hProcess,0,@sBaseName,SizeOf(sBaseName)) > 0 then
sOut := sOut + ' BASE: ' +
sBaseName
else
sOut := sOut + ' BASE: <неизвестно>';
if
GetModuleFilenameEx(hProcess,0,@sFileName,SizeOf(sFileName)) > 0 then
sOut := sOut + ' FILE: ' +
sFileName
else
sOut := sOut + ' FILE: <неизвестно>';
if
GetProcessImageFileName(hProcess, @sImageFileName,
SizeOf(sImageFileName)) > 0 then
sOut := sOut + ' IMAGE: ' +
sImageFileName
else
sOut := sOut + ' IMAGE: <неизвестно>';
CloseHandle(hProcess);
// Обязательно закрываем процесс
end;
slProcesses.Add(sOut); // Добавляем
строчку в TStringList
end;
SetLength(aProcessIds,0); //
Освобождаем память
DisableDebugPrivileges; //
Отключаем отладочные привилегии
Result
:= True;
// Функция выполнилась успешно
end;
end.
Назад |
(с) tripsin aka Орехов Роман, 2006 г.