Лабораторная работа № 1
Монитор процессов и потоков. Часть 2. Дополнительные функции
Цель работы – практическое знакомство с методикой использования функций Win32 API для получения дополнительной информации о процессах, потоках, модулях и драйверах ОС Windows XP.
КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Получение дополнительной информации о процессах и потоках
Задача получения списка выполняющихся в системе процессов и их базовых свойств является одной из основных при выполнении мониторинга ресурсов, как отдельного ПК, так и ЛВС в целом. Для ее решения используются базовые функции Win32 API - CreateToolHelp32Snapshot(), Process32First(), Process32Next(), Thread32First (), Thread32Next(), Module32First(), Module32Next(), Heap32ListFirst(), Heap32ListNext(), рассмотренные в первой части работы.
Для получения дополнительной информации – о времени работы процессов и их потоков, используемой памяти и других ресурсов служат функции Win32 API GetProcessTimes(), GetThreadTimes(), GetProcessIoCounters(), GetProcessHandleCount(), GetProcessMemoryInfo(), GetProcessWorkingSetSize(), EnumDeviceDrivers(), GetDeviceDriverBaseNameA(), GetDeviceDriverFileNameA().
Получение информации о времени выполнения процессов и потоков
Функция
GetProcessTimes(Handle: Thandle; CreateTime, ExitTime, KernelTime, UserTime: TFileTime)
используется для получения времени запуска (создания), времени завершения, времени работы процесса в режиме ядра и пользователя. Процесс задается описателем (Handle), время возвращается ОС в переменных типа TFileTime. Время отсчитывается в 100 наносекундных интервалах с 1.01.1601 по Гринвичу. Для представления времени старта и завершения в привычном формате используются функции
FileTimeToLocalFileTime(Tproc, LocalFileTime : TFileTime)
FileTimeToSystemTime(fTime : TFileTime ; SysT : TSystemTime)
Используя поля структуры TSystemTime, можно получить дату и время старта или завершения процесса с точностью до миллисекунды.
Функция
GetThreadTimes(Handle: Thandle; CreateTime, ExitTime, KernelTime, UserTime: TFileTime)
используется для получения времени запуска (создания), времени завершения, времени работы потока в режиме ядра и пользователя. Поток задается описателем (Handle), время возвращается ОС в переменных типа TFileTime. Время отсчитывается в 100 наносекундных интервалах с 1.01.1601 по Гринвичу. Для представления времени старта и завершения в привычном формате используются функции
FileTimeToLocalFileTime(Tproc, LocalFileTime : TFileTime)
FileTimeToSystemTime(fTime : TFileTime ; SysT : TSystemTime)
Используя поля структуры TSystemTime, можно получить дату и время старта или завершения потока.
Для получения значений описателей процесса и потока в общем случае следует использовать функции OpenProcess() см. часть 1 и OpenThread() – ее аргументы аналогичны. Необходимые значения идентификаторов процесса или потока получаются с помощью функций, рассмотренных в первой части работы.
В частном случае, когда интерес представляет текущий процесс (поток), описатель процесса (потока) возвращается функциями GetCurrentProcess() и GetCurrentThread(). Эти функции не имеют аргументов.
Получение информации счетчиков ввода-вывода и количества описателей (дескрипторов)
Содержимое счетчиков ввода-вывода – количество прочитанных - записанных байт может быть получено функцией
GetProcessIoCounters(Handle: Thandle; pIOCounters : TProcessIOCounters ): bool;
Первый аргумент определяет процесс, второй – указатель на структуру
TProcessIOCounters = record
ReadOperationCount : int64;
WriteOperationCount : int64;
OtherOperationCount : int64;
ReadTransferCount : int64;
WriteOTransferCount : int64;
OtherOTransferCount : int64;
end;
Данная функция содержится в библиотеке kernel32.dll.Поскольку прототип данной функции в файле windows.pas отсутствует, для вызова данной функции (как и всех описанных далее в этой работе функций) используется неявный вызов. Для неявного вызова функции из библиотеки динамической загрузки (DLL) в программе должен быть создан прототип. Пример прототипа
function GetProcessIoCounters(Hprocess: Thandle; PIOCount : TpprocessIOCounters): BOOL; stdcall external 'kernel32.dll';
Прототипы определенных таким образом функций должны содержать:
имя функции (регистр учитывается);
формальные аргументы и их типы;
имя содержащей функцию библиотеки.
Прототипы записываются в разделе implementation. Типы аргументов (не описанные в windows.pas) должны быть описаны в разделе type.
Для рассматриваемого примера в раздел type следует записать
TProcessIOCounters = record
ReadOperationCount : int64;
WriteOperationCount : int64;
OtherOperationCount : int64;
ReadTransferCount : int64;
WriteOTransferCount : int64;
OtherOTransferCount : int64;
end;
TpprocessIOCounters = ^TprocessIOCounters;
а в раздел implementation вставить описание прототипа
function GetProcessIoCounters(Hprocess: Thandle; PIOCount : TpprocessIOCounters): BOOL; stdcall external 'kernel32.dll';
Ошибка в названии библиотеки приводит к появлению на этапе выполнения сообщения «библиотека не найдена», ошибка в написании имени функции (РЕГИСТР учитывается!) – к появлению сообщения «функция XXX не найдена в библиотеке YYY».
Ecли имя функции и имя библиотеки заданы правильно, описанную функцию можно вызывать, указывая правильные типы аргументов.
Функция GetProcessHandleCount(Hprocess: Thandle; PHandCount : TphandCount): Bool из библиотекиkernel32.dllвозвращает указатель на переменную типа Dword, содержащую количество созданных указанных процессом описателей (дескрипторов). Для использования функции необходимо создать прототип для ее вызова из библиотеки, описать переменную HandCount:Dwordи указать вторым аргументом функции адрес этой переменной, например
GetProcessHandleCount (GetCurrentProcess,@HandCount);
Получение информации об используемой процессом памяти
Функция
GetProcessMemoryInfo(Hprocess: Thandle; pmemcount : PPROCESS_MEMORY_COUNTERS) : Bool
из библиотеки Psapi.dll содержит различную информацию об используемой процессом памяти. Процесс задается описателем (Handle), структура, содержащая информацию об использовании памяти
TProcess_Memory_Counters = record
size : Dword; // размер структуры
PageFaultCount: Dword; // количество страничных ошибок
PeakWorkingSetSize:cardinal; // пиковый размер используемой ОП
WorkingSetSize:cardinal; // используемый объем ОП
QuotaPeakPagePoolUsage:cardinal;//максимальный размер страничного пула памяти
QuotaPagePoolUsage : cardinal; // размер страничного пула памяти
QuotaPeakNonPagedPoolUsage : cardinal;//макс размер невыгружаемого пула памяти
QuotaNonPagePollUsage : cardinal; // размер невыгружаемого пула памяти
PageFileUsage : cardinal;
PeakPageFileUsage : cardinal;
PrivateUsage : cardinal;
end;
задается указателем.
Для использования функции необходимо создать ее прототип для вызова из библиотеки Psapi.dll. Перед вызовом функции необходимо в первое поле структуры Process_Memory_Countersзаписать ее размер.
Функция GetProcessWorkingSetSize(Hprocess: Thandle; Min,Max : Cardinal ) возвращает минимальный и максимальный размеры рабочего множества страниц указанного процесса (в байтах). Прототип функции описан в файле windows.pas.
Получение информации о загруженных драйверах
Для получения информации о загруженных в память драйверах и их адресах используются функции EnumDeviceDrivers(), GetDeviceDriverBaseNameA(), GetDeviceDriverFileNameA(), вызываемые из библиотеки Psapi.dll. Прототипы функций имеют следующий вид:
function EnumDeviceDrivers(lp : pointer; cb : DWORD ;
lpcbNeeded : lpDWORD ): BOOL; stdcall external 'psapi.dll';
function GetDeviceDriverBaseNameA(lp : pointer; lpBaseName : lpstr; nSize : DWORD): BOOL; stdcall external 'psapi.dll';
function GetDeviceDriverFileNameA( lp : pointer;
lpFilename : LPTSTR; nSize :DWORD): DWORD ; stdcall external 'psapi.dll';
Функция EnumDeviceDrivers ( lp : pointer; cb : DWORD ; lpcbNeeded : lpDWORD ): BOOL; возвращает массив указателей на загруженные в ОП драйверы. Указатель на массив задается первым аргументом функции, второй аргумент (входной параметр) задает размер массива, если этот размер является недостаточным, требуемый размер возвращается функцией в третьем параметре.
Пример вызова функции
var
pdriver : array [1..138] of cardinal;
lpcbNeeded : dword;
if EnumDeviceDrivers( @pdriver, sizeof(pdriver), @lpcbNeeded )
then
label1.Caption:=inttostr(lpcbNeeded)
Для получения списка имен драйверов служит функция GetDeviceDriverBaseNameA(lp : pointer; lpBaseName : lpstr; nSize : DWORD). Она получает адрес загруженного драйвера (первый аргумент) и размер имени драйвера (третий аргумент) и возвращает имя драйвера.
Пример вызова функции
var
pdriver : array [1..138] of cardinal;
lpcbNeeded : dword;
i : integer;
basename : lpstr;
for I := 1 to lpcbneeded div 4 do
begin
getmem(basename,50);
GetDeviceDriverBaseNameA(pointer(pdriver[i]), BaseName, 50);