страничка tripsin'а


Главная | Статьи | Заметки | Файлы| Ссылки | я
Назад

Дальше

Получение списка процессов. 2 часть. Process Status API.

Скачай демонстрационный проект (26,1 кб)

В Windows NT почему-то не включены Tool Help API. Там имеется другая библиотека Process Status Helper. Скрывается она в файле psapi.dll и позволяет получать информацию и процессах и драйверах устройств. Для работы библиотеки в Delphi в раздел uses надо включить модуль PsAPI. Кстати, в Windows 95/98 этой библиотеки нет.

При пользовании функций этой либы часто требуется дескриптор (хэндл) процесса. Чтобы его получить надо вызвать OpenProcess с PID’ом нужного процесса в параметрах. Так как многие системные процессы не захотят открываться пользовательской проге, то присвоим ей привилегии отладчика с помощью функции EnableDebugPrivileges. (Описание ее смотри в части №0.Подготовка.) Но даже в этом случае наша функция нормально работает только под амином. Под пользователем половина процессов не открывается. То есть PID’ы-то мы получим, но информацию о них извлечь не сможем.

Для получения списка процессов служим функция EnumProcesses:

function EnumProcesses(lpidProcess: LPDWORD; cb: DWORD; var cbNeeded: DWORD): BOOL;

 

lpidProcess – Указатель на буфер под массив PID’ов;

cb – Размер буфера в байтах;

cbNeeded – Количество байтов реально возвращенное функцией в массиве PID’ов;

Если функция успешно выполнилась – она возвращает True. Нет никакой возможности точно определить сколько памяти выделять под буфер. MSDN рекомендует сразу выделить буфер побольше (в примере она выделяет 1 килобайт). Если буфер оказался слишком маленьким, то предупреждение об этом тоже не дается, а просто массив обрезается до размеров буфера. Поэтому, если cbNeeded равно размеру буфера (cb), то надо выделять буфер побольше и вызывать функцию EnumProcesses снова. Так мы и сделаем.

Количество элементов в массиве подсчитывается просто: делим количество возвращенных байт на размер PID’а (то есть на размер DWORD) и получаем количество элементов в массиве.

Дальше, обходя массив в цикле,  получаем PID’ы всех процессов. Получаем для них дескрипторы через OpenProcess. И уже по дескрипторам получаем информацию о процессе. Имя исполняемого файла можно получить двумя способами.

Первый работает только в Windows XP (и наверное еще в Висте) - в библиотеку PsAPI добавлена функция GetProcessImageFileName:

function GetProcessImageFileName(

             hProcess: THandle;     // Дескриптор нужного процесса

             lpFilename: PAnsiChar; // Буфер под имя надо выделять

             nSize: DWORD           // Размер буфера

 ): DWORD; // Возвращает длину строку скопированной в буфер или 0 при ошибке

Она возвращает путь к исполняемому файлу в несколько специфичном формате, типа  -\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 г.

Hosted by uCoz