Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows

Функция VMQuery


Начиная изучать архитектуру памяти в Windows, я пользовался функцией VirtualQuery как «поводырем». Если Вы читали первое издание моей книги, то заметите, что про грамма VMMap была гораздо проще ее нынешней версии, представленной в следую щем разделе. Прежняя была построена на очень простом цикле, из которого перио дически вызывалась функция VirtualQuery, и для каждого вызова я формировал одпу строку, содержавшую элементы структуры MEMORY_BASIC__INFORMATION. Изучая полученные дампы и сверяясь с документацией из SDK (в то время весьма неудачной), я пытался разобраться в архитектуре подсистемы управления памятью. Что ж, с тех пор я многому научился и теперь знаю, что функция VirtualQuery и структура MEMO RY_BASIC_INFORMATION не дают полной картины

Проблема в том, чю в MEMORY_BASIC_INFORMATION возвращается отнюдь не вся информация, имеющаяся в распоряжении системы. Если Вам нужны простейшие дан ные о состоянии памяти по конкретному адресу, VirtualQuery действительно незаме нима. Она отлично работает, если Вас интересует, передана ли по этому адресу фи зическая память и доступен ли он для операций чтения или записи. Но попробуйте e ее помощью узнать общий размер зарезервированного региона и количество блоков в нем или выяснить, не содержит ли этот регион стек потока, — ничего не выйдет

Чтобы получать более полную информацию о памяти, я создал собственную фун кцию и назвал ее VMQuery.

BOOL VMQuery( HANDLE hProcess, PVOID pvAddress, PVMQUERY pVMQ);

По аналогии с VirtualQueryEx она принимает в hProcess описатель процесса, в pvAddress — адрес памяти, а в pVMQ — указатель на структуру, заполняемую самой функцией. Структура VMQUERY (тоже определенная мной) представляет собой вот что.

typedef struct
{

// информация о регионе
PVOID pvRgnBaseAddress;
DWORD dwRgnProtection;

// PAGE_*
SIZE_T RgnSize;
DWORD dwRgnStorage;

// MEM_* Free. Irnage, Mapped, Private
DWORD dwRgnBlocks;
DWORD dwRgnGuardBlks; // если > 0, регион содержит стек потока
BOOL tRqnlsAStack; // TRUE, если регион содержит стек потока


// информация о блоке
PVOID pvBlkBaseAddress;
DWORD dwBlkProtection;

// PAGE_*
SIZE_T BlkSize;

DWORD dwBlkStorage;



// MEM_* Free, Reserve, Image, Mapped, Private

} VMQUERY, *PVMQUERY;

С первого взгляда заметно, что моя структура VMQUERY содержит куда больше информации, чем MEMORY_BASIC_INFORMATION Она разбита (условно, конечно) на две части: в одной — информация и регионе, в другой — информация о блоке (адрес которого указан в параметре pvAddress). Элементы этой структуры описываются в следующейтаблице.

Элемент Описание
pvRgnBaseAddress Идентифицирует базовый адрес региона виртуального адресного про странства, включающего адрес, указанный в параметре pvAddress
dwRgnProtection Сообщает атрибут защиты, присвоенный региону при его резервиро вании.
RgnSize Указывает размер (в байтах) зарезернириванного о региона.
dwRgnStorage Идентифицирует тип физической памяти, используемой группой бло ков данного peгиона: MEM_FREE, MEM_IMAGE, MEM_MAPPED или MEM PRIVATE. Поскольку Windows 98 не различает типы памяти, в этой операционной системе данный элемент содержит либо MEM_FREE, либо MEM_PRIVATE
dwRgnBlocks Содержит значение — число блоков в указанном регионе
dwRgnGuardBlks Указывает число блоков с установленным флагом атрибутов защиты PAGE GUARD. Обычно это значение либо 0, либо 1. Если оно равно 1, то регион скорее всего зарезервирован под стек потока В Windows 98 этот элемент всегда равен 0
fRgnIsAStack Сообщает, есть ли в данном регионе стек потока Результат определя ется на основе взвешенной оценки, так как невозможно дать стопро центной гарантии тому, что в регионе содержится стек.
pvBlkBaseAddress Идентифицирует базовый адрес блока, включающего адрес, указанный в параметре pvAddress,
dwBlkProtection Идентифицирует атрибут защиты блока, включающего адрес, указан ный в параметре pvAddress.
BlkSize Содержит значение — размер блока (в байтах), включающего адрес, указанный в параметре pvAddress.
dwBlkStorage Идентифицирует содержимое блока, включающего адрес, указанный в параметре pvAddress. Принимает одно из значений: MEM FREE, MEM_RESERVE, MEM_IMAGE, MEM_MAPPED или MEM_PRIVATE. В Windows 98 этот элемент никогда не содержит значения MEM IMAGE и MEM MAPPED
<


Чтобы получить всю эту информацию, VMQuery, естественно, приходится выпол нять гораздо болыше операций (в том числе многократно вызывать VirtualQueryEx), а потому она работает значительно медленнее VirtualQueryEx. Так что Вы должны все тщательно взвесить, прежде чем остановить свой выбор па одной из этих функций Если Вам не нужна дополнительная информация, возвращаемая VMQuery, используй те VirtualQuery или VirtualQueryEx.

Листинг файла VMQuerycpp (рис. 14-3) показывает, как я получаю и обрабатываю данные, необходимые для инициализации элементов структуры VMQUERY. (Файлы VMQuery.cpp и VMQueryh содержатся в каталоге 14-VMMap на компакт-диске, прила гаемом к книге.) Чтобы не объяснять подробности обработки данных «на пальцах», я снабдил тексты программ массой комментариев, вольно разбросанных но всему коду.

VMQuery


Содержание раздела