Продолжая рассказ о программных интерфейсах 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.
TH32CS_INHERIT | показывает, что snapshot был унаследован. |
TH32CS_SNAPHEAPLIST | получает список блоков динамически распределенной памяти в адресном пространстве процесса. |
TH32CS_SNAPMODULE | получает список модулей, загруженных процессом. |
TH32CS_SNAPPROCESS | получает список запущенных на локальном компьютере процессов. |
TH32CS_SNAPTHREAD | получает список потоков процесса. |
TH32CS_SNAPALL | включает в себя предыдущие четыре флага, т. е. snapshot будет содержать списки процессов, потоков, модулей и областей динамической памяти. |
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] | полный путь к файлу |
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. |