Получение информации о выполняющихся процессах
23 января 2006 года
Получить информацию о выполняющихся в данный момент на компьютере процессах можно на основе функций API. Для разных платформ эти функции отличаются, как и подключаемые для этих целей модули. Рассмотрим платформу Win95 и WinNT.
В Win95 (Windows 95/98) код может выглядеть следующим образом:
function GetProcessesWin95(var Proc: TProcArray):Integer; var FSnap: THandle; PE: TProcessEntry32; PPE: PProcessEntry32; I: Integer; begin If FSnap > 0 then CloseHandle(FSnap); FSnap:=CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0); PE.dwSize:=SizeOf(PE); I:=0; SetLength(Proc,1000); // заведомо большой массив If Process32First(FSnap,PE) then repeat New(PPE); PPE^:=PE; Proc[I]:=PPE.szExeFile; I:=I+1; until not Process32Next(FSnap, PE); Result:=I; end;
Для работы этого кода нужно подключить в разделе USES модуль TlHelp32 (Help Tool API 32).
Функция возвращает число процессов и записывает их пути в массив-переменную Proc. Тип переменной Proc - обычный массив строк, который нужно описать в разделе описания типов:
type TProcArray = Array of String;
Поясню основные моменты реализации кода. Строка
FSnap:=CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
означает получение "моментального снимка всех процессов". Точнее, в результате ее выполнения мы получаем дескриптор снимка. Функции Process32First и Process32Next позволяют "пробежаться" по всем процессам. О более детальной информации отсылаю читателя к справочной литературе об API.
Для NT-платформы (Windows NT/2000) аналогичный код может выглядеть следующим образом:
function GetProcessesWinNT(var Proc: TProcArray):Integer; var Num: Integer; LP: Array[0..$3FFF-1] of Dword; // заведомо большой массив CB: DWord; CBNeeded:DWord; ProcHndl: THandle; ModHand: HModule; ModName: array [0..MAX_PATH] of Char; I: Integer; begin EnumProcesses(@LP,CB,CBNeeded); Num:= CBNeeded div SizeOf(DWORD); SetLength(Proc,Num); For I:=0 to Num-1 do begin ProcHndl:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,False,LP[I]); If GetModuleFileNameEx(ProcHndl,ModHand,ModName,SizeOf(ModName))> 0 then Proc[I]:=ModName else Proc[I]:='Unknown'; end; IF ProcHndl > 0 then CloseHandle(ProcHndl); Result:=Num; end;
Здесь уже используется модуль PSAPI, который необходимо включить в раздел USES. Кому интересно разобраться в деталях данного кода отсылаю к справке по API.
Замечу, что под управлением WINDOWS 2000, в списке процессов я наблюдал иногда "абракадабру" по путям некоторых процессов. Предлагаю в этом вопросе читателю разобраться самостоятельно, а у меня пока до этого не дошли руки. Тем не менее, считаю, что данная статья может послужить хорошим подспорьем, для всех интересующихся данным вопросом.
В конце приведу код для определения платформы компьютера, поскольку он может понадобиться при реализации кода для вывода списка процессов. Оставляю его без комментариев.
function GetPlatform: String; var VI: TOSVersionInfo; begin VI.dwOSVersionInfoSize:=SizeOf(VI); GetVersionEx(VI); Case VI.dwPlatformId of Ver_Platform_Win32s: Result:= 'Win32s'; Ver_Platform_Win32_Windows: Result:='Win95'; Ver_Platform_Win32_NT: Result:='WinNT' else Result:='Unknown Platform'; end; end;
В моем модуле SysInfo v.3.00 можно найти функции получения информации о выполняемых процессах и о другой системной информации.
Оставить комментарий
Комментарии
Чтобы OpenProcess() работал более успешно, надо вызывающей программе повысить привилегии до уровня SeDebugPrivilege (константа SE_DEBUG_NAME). Это дает доступ к процессам вплоть до PROCESS_ALL_ACCESS. Без этого OpenProcess() может не получить \"хэндла\" с запрошенными флагами доступа.
Делается это примерно так. Вставляем до цикла \"For I:=0 to Num-1 do...\" следующий код:
OpenThreadToken(
GetCurrentThread(), //наша программы
TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
FALSE,
@hToken
);
tp.PrivilegeCount:=0;
tp.Privileges[0].Attributes:=0;
tp.Privileges[0].Luid:=0;
cbT:= sizeof(TOKEN_PRIVILEGES);
LookupPrivilegeValue( 0, SE_DEBUG_NAME, @luidMod );
tp.PrivilegeCount:= 1;
tp.Privileges[0].Luid:= luidMod;
tp.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken, false, @tp, cbT, 0, 0 );
if (hToken <> 0) then CloseHandle(hToken); //больше не нужен
А в раздел var добавляем переменные:
hToken : Cardinal;
tp: TOKEN_PRIVILEGES;
luidMod: LUID;
Проверил этот метод в Lazarus. В uses подключил модуль Windows. В Delphi должно быть тоже самое. В списке процессов по-прежнему неопределенные процессы присутствуют, но их всего несколько - это системныее процессы самого высшего уровня. Увеличение до PROCESS_ALL_ACCESS флага в OpenProcess() ситуацию не улучшает.
Автор