ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 09.02.2021
Просмотров: 167
Скачиваний: 1
7
Windows 95/98: использование ToolHelp32
ToolHelp32 — это семейство функций и процедур, составляющих подмножество Win32 API, которые позволяют получить сведения о некоторых низкоуровневых аспектах работы ОС. В частности, сюда входят функции, с помощью которых можно получить информацию обо всех процессах, выполняющихся в системе в данный момент, а также потоках, модулях и кучах, принадлежащих каждому процессу.
Типы и определения функций ТооlНе1р32 размещаются в модуле ТlНе1р32, поэтому при работе с этими функциями нужно включить его имя в список инструкции uses.
Моментальные снимки
Благодаря многозадачной природе среды Win32 такие объекты, как процессы, потоки, модули и т.п., постоянно создаются, разрушаются и модифицируются. И поскольку состояние компьютера непрерывно изменяется, системная информация, которая, возможно, будет иметь значение в данный момент, через секунду уже никого не заинтересует. Например, предположим, что вы хотите написать программу для регистрации всех модулей, загруженных в систему. Поскольку операционная система в любое время может прервать выполнение потока, отрабатывающего вашу программу, чтобы предоставить какие-то кванты времени другому потоку в системе, модули теоретически могут создаваться и разрушаться даже в момент выборки информации о них.
В этой динамической среде имело бы смысл на мгновение заморозить систему, чтобы получить такую системную информацию. В ToolHelp32 не предусмотрено средств замораживания системы, но есть функция, с помощью которой можно сделать "снимок" системы в заданный момент времени. Эта функция называется CreateToolhelp32Snapshot(), и ее объявление выглядит следующим образом:
function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): THandle;
stdcall;
Параметр dwFlags означает тип информации, подлежащий включению в моментальный снимок. Этот параметр может иметь одно из перечисленных в табл. значений.
-
Значение
Описание
TH32CS_INHERIT
Означает, что дескриптор снимка будет наследуемым
TH32CS_SNAPALL
Эквивалентно заданию значений th32cs_snapheaplist, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS и TH32CS_SNAPTHREAD
TH32CS_SNAPHEAPLIST
Включает в снимок список куч заданного процесса Win32
TH32CS_SNAPMODULE
Включает в снимок список модулей заданного процесса Win32
TH32CS_SNAPPROCESS
Включает в снимок список процессов Win32
TH32CS_SNAPTHREAD
Включает в снимок список потоков Win32
Функция CreateToolhelp32Snapshot() возвращает дескриптор созданного снимка или -1 в случае ошибки. Возвращаемый дескриптор работает подобно другим дескрипторам Win32 относительно процессов и потоков, для которых он действителен.
Следующий код создает дескриптор снимка, который содержит информацию обо всех процессах, загруженных в настоящий момент (EToolHelpError — это исключительная ситуация, определенная программистом):
var
Snap: THandle;
begin
Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if Snap = -1 then
raise EToolHelpError.Create('CreateToolHelp32Snapshot failed');
end;
Для освобождения связанных с ним ресурсов используйте функцию CloseHandle ().
Обработка информации о процессах
Имея дескриптор снимка, содержащий информацию о процессах, можно воспользоваться двумя функциями ТооlНе1р32, которые позволяют последовательно просмотреть сведения обо всех процессах в системе. Функции Process32First() и Process32Next() определены следующим образом:
function Process32First(hSnapshot: THandle; var lppe: TProcessEntry32):BOOL; stdcall;
function Process32Next(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;
Первый параметр у обеих функций является дескриптором снимка, возвращаемым функцией CreateToolhelp32Snapshot().Второй параметр, lppe, представляет собой запись TProcessEntry32, которая передается по ссылке. По мере прохождения по элементам перечисления функции будут заполнять эту запись информацией о следующем процессе. Запись TProcessEntry32 определяется так:
type
TProcessEntry32 = record
dwSize: DWORD;
cntUsage: DWORD;
th32ProcessID: DWORD;
th32DefaultHeapID: DWORD;
th32ModuleID: DWORD;
cntThreads: DWORD;
th32ParentProcessID: DWORD;
pcPriClassBase: Longint;
dwFlags: DWORD;
szExeFile: array[0..MAX_PATH - 1] of Char;
end;
-
В поле dwSize содержится размер записи TProcessEntry32. До использования этой записи поле dwSize должно быть инициализировано значением SizeOf (TProcessEntry32).
-
В поле cntUsage хранится значение счетчика ссылок процесса. Когда это значение станет равным нулю, операционная система выгрузит процесс.
-
В поле th32ProcessID содержится идентификационный номер процесса.
-
Поле th32DefaultHeapID предназначено для хранения идентификатора (ID) для кучи процесса, действующей по умолчанию. Этот ID имеет значение только для функций Тоо1Не1р32, и его нельзя использовать с другими функциями Win32.
-
Поле thModulelD идентифицирует модуль, связанный с процессом. Это поле имеет значение только для функций TooIHelp32.
-
По значению поля cntThreads можно судить о том, сколько потоков начало выполняться в данном процессе.
-
Поле th32ParentProcessID идентифицирует родительский процесс для данного процесса.
-
В поле pcPriClassBase хранится базовый приоритет процесса. Операционная система использует это значение для управления работой потоков.
-
Поле dwFlags зарезервировано.
-
В поле szExeFile содержится строка с ограничивающим нуль-символом, которая представляет собой путь и имя файла ЕХЕ-программы или драйвера, связанного с данным процессом.
После создания снимка, содержащего информацию о процессах, для опроса данных по каждому процессу следует вызвать сначала функцию Process32First(), а затем вызывать функцию Process32Next() до тех пор, пока она не вернет значение False.
Обработка информации о потоках
Для составления списка потоков некоторого процесса в Тоо1Не1р32 предусмотрены две функции, которые аналогичны функциям, предназначенным для регистрации процессов: Thread32First() и Thread32Next(). Эти функции объявляются следующим образом:
function Thread32First(hSnapshot: THandle; var lpte: TThreadEntry32): BOOL; stdcall;
function Thread32Next(hSnapshot: THandle; var lpte: TThreadENtry32): BOOL; stdcall;
Помимо обычного параметра hSnapshot, этим функциям также передается по ссылке параметр типа TThreadEntry32. Как и в случае функций, работающих с процессами, каждая из них заполняет запись TThreadEntry32, объявление которой имеет вид
type
TThreadEntry32 = record
dwSize: DWORD;
cntUsage: DWORD;
th32ThreadID: DWORD;
th320wnerProcessID: DWORD;
tpBasePri: Longint;
tpDeltaPri: Longint;
dwFlags: DWORD;
end;
-
Поле dwSize определяет размер записи, и поэтому оно должно быть инициализировано значением SizeQf (TThreadEntry32) до использования этой записи.
-
В поле cntUsage содержится счетчик ссылок данного потока. При обнулении этого счетчика поток выгружается операционной системой.
-
Поле th32ThreadID представляет собой идентификационный номер потока, который имеет значение только для функций TooIHelp32.
-
В поле th32OwnerProcessID содержится идентификатор (ID) процесса, которому принадлежит данный поток. Этот ID можно использовать с другими функциями Win32.
-
Поле tpBasePri представляет собой базовый класс приоритета потока. Это значение одинаково для всех потоков данного процесса. Возможные значения этого поля обычно лежат в диапазоне от 4 до 24. Описания этих значений приведены в табл.
Допустимые значения класса приоритета потоков
|
значения «пспспис |
Описание |
|
4 |
Ожидающий |
|
8 |
Нормальный |
|
13 |
Высокий |
|
24 |
Реальное время |
-
Поле tpDeltaPri представляет собой дельта-приоритет (разницу), определяющий величину отличия реального приоритета от значения tpBasePri. Это число со знаком, которое в сочетании с базовым классом приоритета отображает общий приоритет потока.
-
Поле dwFlags в данный момент зарезервировано и не должно использоваться.
Обработка информации о модулях
Опрос модулей выполняется практически так же, как опрос процессов или потоков. Для этого в Тоо1Не1р32 предусмотрены две функции: Module32First() и Module32Next(), которые определяются следующим образом:
function Module32First(hSnapshot: THandle; var lpme: TModuleEntry32): BOOL; stdcall;
function Module32Next(hSnapshot: THandle; var lpme: TModuleEntry32): BOOL; stdcall;
Первым параметром в обеих функциях является дескриптор снимка, а вторым var-параметром — запись TModuleEntry32. Ее определение имеет следующий вид:
tуре
TModuleEntry32 = record
dwSize: DWORD;
th32ModuleID: DWORD;
th32ProcessID: DWORD;
GlblcntUsage: DWORD;
ProccntUsage: DWORD;
modBaseAddr: РВУТЕ;
modBaseSize: DWORD;
hModule: HMODULE;
szModule: array[0..MAX_MODULE_NAME32 + 1] of Char;
szExePath: array[0..MAX_PATH - 1] of Char;
end;
-
Поле dwSize определяет размер записи и поэтому должно быть инициализировано значением SizeOf (TModuleEntry32) до использования этой записи.
-
Поле th32ModuleID представляет собой идентификатор модуля, который имеет значение только для функций TooIHelp32.
-
Поле th32ProcessID содержит идентификатор (ID) опрашиваемого процесса. Этот ID можно использовать с другими функциями Win32.
-
Поле GlblcntUsage содержит глобальный счетчик ссылок данного модуля.
-
Поле ProccntUsage содержит счетчик ссылок модуля в контексте процесса-владельца.
-
Поле modBaseAddr представляет собой базовый адрес модуля в памяти. Это значение действительно только в контексте идентификатора процесса th32ProcessID.
-
Поле modBaseSize определяет размер (в байтах) модуля в памяти.
-
В поле hModule содержится дескриптор модуля. Это значение действительно только в контексте идентификатора процесса th32ProcessID.
-
В поле szModule содержится строка с именем модуля, завершающаяся нуль-символом.
-
Поле szExepath предназначено для хранения строки с ограничивающим нуль-символом, содержащей полный путь модуля.
Обработка информации о динамической памяти (кучах)
Опрос куч несколько сложнее опроса других типов объектов. В Тоо1Не1р32 предусмотрены четыре функции, с помощью которых можно получить информацию о кучах. Первые две, Heap32ListFirst() и Heap32ListNext(позволяют выполнить проход по всем кучам процесса, а две другие, Heap32First() и Heap32Next(), используются для получения более подробной информации обо всех блоках внутри отдельной кучи.
Функции Heap32ListFirst() и Heap32ListNext() определяются следующим образом:
function Heap32ListFirst(hSnapshot: THandle; var lphl: THeapList32): BOOL; stdcall;
function Heap32ListNext(hSnapshot: THandle; var lphl: THeapList32): BOOL; stdcall;
И вновь первый параметр является дескриптором снимка, а второй (lphl) представляет собой запись типа THeapList32, передаваемую по ссылке. Определение этой записи имеет следующий вид:
type
THeapList32 = record
dwSize: DWORD;
th32ProcessID: DWORD;
th32HeapID: DWORD;
dwFlags: DWORD;
end;
-
Поле dwSize определяет размер записи, и поэтому оно должно быть инициализировано значением SizeOf (THeapList32) до использования этой записи.
-
В поле th32ProcessID содержится идентификатор (ID) процесса-владельца.
-
В поле th32HeapID содержится идентификатор (ID) кучи. Этот ID имеет значение только для заданного процесса, и его можно использовать только с функциями Тоо1Не1р32.
-
В поле dwFlags хранится признак, который определяет тип кучи. В качестве значения этого поля может использоваться либо константа HF32 DEFAULT (которая означает, что текущая куча является стандартной кучей процесса), либо константа HF32_SHARED (которая означает, что текущая куча является разделяемой обычным способом).
Функции Heap32First() и Heap32Next() определяются следующим образом:
function Heap32First(var lphe: THeapEntry32; th32ProcessID, th32HeapID: DWORD): BOOL; stdcall;
function Heap32Next(var lphe: THeapEntry32): BOOL; stdcall;
Списки параметров этих функций немного отличаются от соответствующих списков функций, связанных с перечислением процессов, потоков, модулей. Эти функции предназначены для перечисления блоков данной кучи в данном процессе, а не некоторых свойств одного процесса, вызове функции Heap32First() параметры, установленные в полях th32ProcessID и ;32HeapID, должны быть равны значениям одноименных полей записи THeapList32, заполненной с помощью функций Heap32ListFirst() или Heap32ListNext(). Var-параметр lphe функций Heap32First() и Heap32Next() имеет тип THeapEntry32. Эта запись содержит дескриптивную информацию, относящуюся к блоку кучи, и ее определение имеет следующий вид:
type
THeapEntry32=record
dwSize: DWORD;
hHandle: THandle;//дескриптор этого блока кучи
dwAddress: DWORD;//линейный адрес начала блока
dwBlockSize: DWORD;//размер блока в байтах
dwFlags: DWORD;
dwLockCount: DWORD;
dwResvd: DWORD;
th32ProcessID: DWORD; // Процесс-владелец
th32HeapID: DWORD;// Идентификатор кучи в нем
end;
-
Поле dwSize определяет размер записи и поэтому должно быть инициализировано значением SizeOf (THeapEntry32) до использования этой записи.
-
В поле hHandle содержится дескриптор блока кучи.
-
Поле dwAddress представляет собой линейный адрес начала блока кучи.
-
В поле dwBlockSize содержится размер в байтах этого блока кучи.
-
В поле dwFlags хранится признак, который определяет тип блока кучи. Это поле может иметь одно из значений:
LF32_FIXED – блок памяти имеет фиксированное местонахождение
LF32_FREE – блок памяти не используется
LF32 MOVEABLE – блок памяти можно перемещать
-
Поле dwLockCount представляет собой счетчик блокировок блока памяти. Это значение увеличивается на единицу при каждом вызове процессом функции GlobalLock() или LосаlLоск().
-
Поле dwResvd зарезервировано в данный момент и не должно использоваться.
-
В поле th32ProcessID содержится идентификатор процесса-владельца.
-
Поле th32HeapID является идентификатором кучи, которой принадлежит блок.
Поскольку до составления списка блоков кучи вам придется сначала составить список куч, код опроса блоков кучи немного сложнее. В приведеннм ниже методе TDetailForra.WalkHeaps() вложены Heap32First()/Heap32Next() внутрь цикла Heap32ListFirst()/Heap32ListNext(). В этом методе вводится дополнительный уровень сложности путем добавления указателя на объекты типа записи PHeapEntry32 в ту часть массива DetailLists, которая относится к списку куч
procedure WalkHeaps;
{ Использует функции ToolHelp32 для составления списка куч }
var
HL: THeapList32;
НЕ: THeapEntry32;
РНЕ: PHeapEntry32;
begin
DetailLists[ltHeap].Clear;
HL.dwSize := SizeOf(HL);
HE.dwSize:=SizeOf(HE);
If Heap32ListFirst(FCurSnap, HL) then
repeat
if Heap32First(HE, HL.th32ProcessID, HL.th32HeapID) then
repeat
{ Необходимо создать копию записи THeapList32, что позволит
сохранить информацию для просмотра сведений о куче позднее}
New(РНЕ);
РНЕ^ := НЕ;
DetailLists[ltHeap].AddObject(Format(SHeapStr, [HL.th32HeapID, Pointer(HE.dwAddress), HE.dwBlockSize, GetHeapFlagString(HE.dwFlags) ]), TObject(PHE));
until not Heap32Next(HE);
until not Heap32ListNext(FCurSnap, HL);
HeapListAlloc := True;
end;