Продолжая рассказ о программных интерфейсах Windows NT/2000, в этой статье я остановлюсь на небольшой, но интересной библиотеке Tool Help Library (далее THL).

Без сомнения, разработчики операционных систем компании Microsoft, которым, я надеюсь, читатель мне позволит выразить признательность, не смыкают глаз в заботе о программистах, коим приходится создавать приложения для этих ОС. В базовые API входят самые разнообразные интерфейсы, существенно облегчающие наш нелегкий труд.

THL - один из таких интерфейсов. Данная библиотека позволяет получить информацию о состоянии работающих на локальном компьютере приложений. Вообще говоря, библиотека предназначена для написания всякого рода отладчиков, но, я думаю, область ее применения на самом деле заметно шире. Описанная технология не работает на Windows NT, только на Windows 2000, 95/98/Me. Демонстрационная программа, исходные тексты которой находятся по адресу: http://members.xoom.com/alex_ep/source/th.zip, транслировалась в Microsoft Visual C++ 6.0 SP5 и тестировалась под управлением Windows 2000 Professional SP1.

Снимки системы

В основе THL лежит понятие «snapshot» - мгновенного снимка состояния запущенных приложений. Перед вызовом всех функций библиотеки необходимо создать snapshot. Это осуществляется вызовом функции

HANDLE WINAPI CreateToolhelp32Snapshot
(DWORD dwFlags, DWORD th32ProcessID );

Параметр dwFlags указывает, какая именно информация интересует пользователя. Его значения приведены в Таблице 1.

Параметр th32ProcessID идентифицирует процесс, состояние которого исследуется. Он необходим при использовании dwFlags со значениями TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE и TH32CS_SNAP-THREAD. В остальных случаях этот параметр игнорируется.

Так, например, для получения списка модулей процесса dwProcessID необходим следующий вызов:

hSnapshot = CreateToolhelp32Snapshot
( TH32CS_SNAPMODULE,dwProcessID );

Уничтожается объект snapshot стандартным вызовом CloseHandle( hSnapshot );

Все ошибки, возникающие при выполнении функций THL, возвращаются стандартным вызовом GetLast-Error и FormatMesssage.

Список процессов

Чтобы получить список действующих в настоящий момент процессов, необходимо написать код, пример которого приведен в Листинге 1.

В примере используются две функции:

BOOL WINAPI Process32First(  HANDLE 
hSnapshot, LPPROCESSENTRY32 lppe )

и

BOOL WINAPI Process32Next(  HANDLE
 hSnapshot, LPPROCESSENTRY32 lppe ).

В обеих функциях два параметра. Первый - дескриптор, возвращаемый предыдущим вызовом CreateToolhelp-32Snapshot, а второй указывает на структуру PROCESSENTRY32, в которой возвращается результат выполнения функции. Перед вызовом Process32First необходимо установить в поле dwSize структуры PROCES-SENTRY32 значение, равное размеру самой структуры - sizeof(PROCES-SENTRY32), иначе функция вернет ошибку.

Список модулей, загруженных процессом

В процессе работы практически любого приложения Win32 загружаются те или иные библиотеки, компоненты и другие программные модули. Естественно, возникает желание получить список загруженных модулей. Для этого в THL также предусмотрен простой механизм. В Листинге 2 приведен фрагмент кода, иллюстрирующий решение этой задачи.

В нем, в первую очередь, вызывается CreateToolhelp32Snapshot с параметрами TH32CS_SNAPMODULE и идентификатором процесса, модули которого нас интересуют. Далее, как и в предыдущем примере, в поле dwSize, но теперь уже структуры MODULEENTRY32, устанавливается значение, равное ее размеру. Кстати, это необходимо делать для всех функций перечисления THL.

Цикл перебора ничем не отличается от рассмотренного в предыдущем примере. Разве что он использует структуру MODULEENTRY32, в которую возвращается информация о модуле. Описание полей этой структуры содержится в Таблице 2.

Потоки процесса

Механизм работы с потоками процесса идентичен механизму, описанному для модулей, только вызываются функции Thread32First и Thread32Next, а вместо структуры MODULEENTRY32 используется THREADENTRY32.

Доступ к памяти процесса

Известно, что в Win32 получить доступ к памяти одного процесса из другого невозможно. Тем не менее в THL есть функция, позволяющая получить копию блока памяти другого процесса:

BOOL WINAPI Toolhelp32Read
ProcessMemory
( DWORD th32ProcessID, LPCVOID
 lpBaseAddress, 
 LPVOID lpBuffer,  DWORD cbRead,
 LPDWORD
 lpNumberOfBytesRead  );

Параметры у этой замечательной функции следующие:

th32ProcessID

[in] Идентификатор процесса, блок памяти которого необходимо скопировать. Если этот параметр равен нулю, то копируется память из текущего процесса.

lpBaseAddress

[in] Адрес в адресном пространстве указанного процесса, начиная с которого копируется информация. Перед выполнением операционная система проверяет, вся ли указанная память доступна для чтения. Если это не так, возвращается FALSE.

lpBuffer

[out] Указатель на буфер, в который должны быть скопированы данные.

cbRead 

[in] Размер буфера в байтах.

lpNumberOfBytesRead 

[out] Количество скопированных байтов.

А как узнать, где в адресном пространстве процесса находятся данные? В самом общем случае на этот вопрос ответить невозможно. Но для динамически распределяемой памяти (heap) THL предоставляет функции, эту проблему решающие.

Исследование динамической памяти процесса

Для выделения области в виртуальной памяти используется функция HeapCreate, которая создает соответствующий объект (heap) в адресном пространстве процесса. Для выделения памяти внутри этого блока используется функция HeapAlloc. Все остальные функции работы с динамической памятью (GlobalAlloc, malloc, calloc и т. д.) сводятся к использованию этого механизма, который мы не будем здесь подробно рассматривать.

Очевидно, что нужно уметь находить список выделенных областей виртуальной памяти и для каждого из них - список выделенных блоков. Посмотрим, как это делается с помощью функций THL (см. Листинг 3). В терминах THL область памяти называется heap, множество областей памяти - heap list, а выделенному внутри нее блоку соответствует термин «block of a heap».

Первый цикл с помощью функций Heap32ListFirst и Heap32ListNext возвращает список блоков памяти, которые были распределены. Зная идентификатор процесса и идентификатор области виртуальной памяти, который возвращается в поле th32HeapID структуры HEAPLIST32, можно просмотреть, как распределяется память внутри этого блока. Выделенные области памяти можно получить с помощью функций Heap32First и Heap32-Next. Они возвращают структуру HEAPENTRY32, описание полей которой приведено в Таблице 3.

Зная значения полей dwAddress и dwBlockSize, с помощью функции Toolhelp32ReadProcessMemory нетрудно получить данные, находящиеся в динамической памяти процесса.

В заключение остается добавить, что информацию о Tool Help Library можно найти в MSDN по адресу: http://msdn.microsoft.com/library/ psdk/helplib/toolhelp_5pfd.htm.

Александр ЭПШТЕЙН - руководитель отдела разработки компании Internet Investment Group. С ним можно связаться по адресу: alex_ep@hotmail.com.


Таблица 1. Значения параметра dwFlags-функции. CreateToolhelp32Snapshot.
TH32CS_INHERITпоказывает, что snapshot был унаследован.
TH32CS_SNAPHEAPLIST получает список блоков динамически распределенной памяти в адресном пространстве процесса.
TH32CS_SNAPMODULE получает список модулей, загруженных процессом.
TH32CS_SNAPPROCESS получает список запущенных на локальном компьютере процессов.
TH32CS_SNAPTHREAD получает список потоков процесса.
TH32CS_SNAPALL включает в себя предыдущие четыре флага, т. е. snapshot будет содержать списки процессов, потоков, модулей и областей динамической памяти.

назад


Таблица 2. Описание полей структуры MODULEENTRY32.
DWORD dwSize размер структуры в байтах
DWORD th32ModuleID ID модуля
DWORD th32ProcessID ID процесса модуля
DWORD GlblcntUsage общее для системы количество обращений к модулю
DWORD ProccntUsage количество обращений к модулю, сделанных из текущего процесса
BYTE * modBaseAddr адрес модуля в адресном пространстве процесса
DWORD modBaseSize размер модуля
HMODULE hModule дескриптор модуля в контексте процесса
TCHAR szModule [MAX_MODULE_NAME32 + 1] имя модуля
TCHAR szExePath[MAX_PATH] полный путь к файлу

назад


Таблица 3. Описание полей структуры HEAPENTRY32.
SIZE_T dwSize размер структуры HEAPENTRY32 в байтах.
HANDLE hHandle дескриптор блока памяти в адресном пространстве процесса.
ULONG_PTR dwAddress адрес начала блока памяти.
SIZE_T dwBlockSize размер блока памяти.;
DWORD dwFlags флаги, описывающие область памяти. Этот параметр может принимать следующие значения:
LF32_FIXED область памяти не может быть перемещена операционной системой;
LF32_FREE блок памяти не используется;
LF32_MOVEABLE область памяти выделена и может перемещаться.
DWORD dwLockCount количество вызовов функции GlobalLock (в Win32 LocalLock синоним функции GlobalLock), которые были сделаны для этого блока памяти.
DWORD dwResvd зарезервировано.
DWORD th32ProcessID ID процесса, в контексте которого выделена память.
ULONG_PTR th32HeapID идентификатор блока памяти, выделенного функцией HeapCreate.