Puc. 3.6.4. Пример программы с выделением динамической памяти.
Трансляция программы на Рис. 3.6.4.
MASM32:
ML /С /coff /DMASM MEM.ASM LINK /SUBSYSTEM:CONSOLE MEM.OBJTASM32:
TASM32 /ml MEM.ASM TLINK32 -ap MEM.OBJ
Операционная система Windows предоставляет также группу функций,
осуществляющих управление виртуальной памятью. Основной функцией этой группы
является функция VirtualAlloc
. Вот параметры этой функции:
- 1-й параметр. Адрес блока памяти для резервирования или передачи ему физической памяти.
- 2-й параметр. Размер блока.
- 3-й параметр. Может быть равен
MEM_RESERVE
- для резервирования блока, илиMEM_COMMIT
- для резервирования и передачи ему физической памяти. - 4-й параметр. Определяет уровень защиты блока. Он может быть, например,
равен
PAGE_READONLY
илиPAGE_READWRITE
, или другой константе, определенной в документации Windows. - Возвращает функция виртуальный адрес блока памяти.
Суть данной функции заключается в том, что Вы можете зарезервировать блок памяти, который не спроецирован на физическую память, а затем сделать так, чтобы этот блок (или часть его) был спроецирован на физическую память. После чего этот блок памяти можно уже использовать.
Другая функция, VirtualFree
, может освобождать блоки,
задействованные функцией VirtualAlloc
. Первым параметром этой
функции является адрес блока. Вторым параметром функции является размер
освобождаемого блока. Третий параметр функции может принимать значение
МЕМ_DЕСОММIТ
либо значение MEM_RELEASE
. В первом
случае блок (или его часть) перестает быть отображаемым. Во втором случае весь
блок перестает быть зарезервированным. При этом значении второй параметр
обязательно должен быть равен нулю.
Фильтры (HOOKS). Мы рассмотрим весьма действенное средство, чаще всего используемое для отладки программ. Средство это называют фильтрами или ловушками52. Смысл его заключается в том, что Вы при желании можете отслеживать сообщения как в рамках одного приложения, так и в рамках целой системы. В этой связи фильтры делят на глобальные (в рамках всей системы) и локальные (в рамках данного процесса). Работая с фильтрами, надо иметь в виду, что они могут существенным образом затормозить работу всей системы. Особенно это касается глобальных фильтров. С точки зрения программирования мы просто определяем функцию, которая вызывается системой при возникновении некоторого события. Можно также говорить о сообщении, приходящем на функцию фильтра.
Рассмотрим некоторые средства для работы с фильтрами. Ниже перечислены основные типы фильтров или сообщения.
WH_CALLWNDPROC
- фильтр срабатывает, когда вызывается функцияSendMessage
.WH_CALLWNDPROCRET
- фильтр срабатывает, когда функцияSendMessage
возвращает управление.WH_CBT
- сообщение приходит, когда что-то происходит с окном.WH_DEBUG
- данное сообщение посылается перед тем, как послать сообщение какому-либо другому фильтру.WH_GETMESSAGE
- данный фильтр срабатывает, когда функцияGetMessage
принимает какое-либо сообщение из очереди.WH_JOURNALRECORD
- данное сообщение приходит на процедуру фильтра, когда система удаляет из очереди какое-либо сообщение.WH_JOURNALPLAYBACK
- вызывается за предыдущим вызовом (WH_JOURNALRECORD
).WH_KEYBOARD
- сообщение приходит, когда происходят клавиатурные события.WH_MOUSE
- аналогично предыдущему, но относится к событиям с мышью.WH_MSGFILTER
- вызывается в случае событий ввода, которые произошли с диалоговым окном, меню, полосой прокрутки, но до того, как эти события были обработаны в пределах данного процесса.WH_SHELL
- данный фильтр срабатывает, когда что-то происходит с Windows-оболочкой.WH_SYSMSGFILTER
- аналогично сообщениюWH_MSGFILTER
, но относится ко всей системе.
Фильтр устанавливается при помощи функции SetWindowsHookEx
.
Рассмотрим параметры этой функции.
- 1-й параметр. Тип фильтра, из тех, что мы перечислили выше.
- 2-й параметр. Адрес процедуры фильтра. Если Вы создаете для всей системы, то
эта процедура должна находиться в динамической библиотеке. Исключение составляют
лишь два типа фильтра:
WH_JOURNALRECORD
иWH_JOURNALPLAYBACK
. - 3-й параметр. Дескриптор динамической библиотеки, если фильтр предназначен для всей системы. Исключение составляют два, уже упомянутых типа фильтра.
- 4-й параметр. Идентификатор потока, если Вы хотите следить за одним из потоков. Если значение этого параметра равно нулю, то создается фильтр для всей системы. Вообще говоря, поток может относиться и к Вашему, и к "чужому" процессу.
- Функция
SetWindowsHookEx
возвращает дескриптор фильтра.
Функция фильтра получает три параметра. Первый параметр определяет произошедшее событие в зависимости от типа фильтра. Два последующих параметра расшифровывают это событие. Поскольку для каждого типа фильтра может быть несколько событий, я не буду их перечислять. Их можно найти в справочном руководстве.
По окончании работы фильтр обязательно должен быть закрыт с помощью функции
UnhookWindowsHookEx
, единственным параметром которой является
дескриптор фильтра.
Фильтр, вообще говоря, есть лишь некоторое звено в вызываемой системой
цепочке, поэтому следует из своей процедуры фильтра вызвать функцию
CallNextHookEx
, которая передаст нужную информацию по цепочке.
Параметры этой функции:
- 1-й параметр. Дескриптор Вашего фильтра.
- 2,3,4-й параметры в точности соответствуют трем параметрам, переданным Вашей процедуре фильтра.
Ниже на Рис. 3.6.5 приводится пример простого фильтра, который отлавливает все произошедшие в системе нажатия клавиши "пробел". Обратите внимание, что поскольку устанавливаемый нами фильтр является глобальным, мы помещаем процедуру фильтра в динамическую библиотеку.
// файл dial.rc для программы DLLEX.ASM // определение констант #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x00010000L // определение диалогового окна DIAL1 DIALOG 0, 0, 240, 120 STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX CAPTION "Пример программы с фильтром" FONT 8, "Arial" { } ; основной модуль DLLEX.ASM, ; устанавливающий фильтр в динамической библиотеке .386P ; плоская модель .MODEL FLAT, stdcall ; константы ; сообщение приходит при закрытии окна WM_CLOSE equ 10h WM_INITDIALOG equ 110h WH_KEYBOARD equ 2 ; структура сообщения MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS ; прототипы внешних процедур IFDEF MASM ; MASM EXTERN UnhookWindowsHookEx@4:NEAR EXTERN SetWindowsHookExA@16:NEAR EXTERN EndDialog@8:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN GetProcAddress@8:NEAR EXTERN LoadLibraryA@4:NEAR EXTERN FreeLibrary@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN MessageBoxA@16:NEAR ; директивы компоновщику для подключения библиотек includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE EXTERN UnhookWindowsHookEx:NEAR EXTERN SetWindowsHookExA:NEAER EXTERN EndDialog:NEAR EXTERN DialogBoxParamA:NEAR EXTERN GetProcAddress:NEAR EXTERN LoadLibraryA:NEAR EXTERN FreeLibrary:NEAR EXTERN ExitProcess:NEAR EXTERN MessageBoxA:NEAR UnhookWindowsHookEx@4 = UnhookWindowsHookEx SetWindowsHookExA@16 = SetWindowsHookExA EndDialog@8 = EndDialog DialogBoxParamA@20 = DialogBoxParamA GetProcAddress@8 = GetProcAddress LoadLibraryA@4 = LoadLibraryA FreeLibrary@4 = FreeLibrary ExitProcess@4 = ExitProcess MessageBoxA@16 = MessageBoxA ; директивы компоновщику для подключения библиотек includelib c:\tasm32\lib\import32.lib ENDIF ; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' MSG MSGSTRUCT <?> HINST DD 0 ; дескриптор приложения PA DB "DIAL1",0 LIBR DB 'DLL2.DLL',0 HLIB DD ? APROC DD ? HH DD ? ATOH DD ? IFDEF MASM NAMEPROC DB '_HOOK@0',0 NAMEPROC1 DB '_TOH@0',0 ELSE NAMEPROC1 DB '_TOH',0 NAMEPROC DB 'HOOK',0 ENDIF _DATA ENDS ; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; загрузить библиотеку PUSH OFFSET LIBR CALL LoadLibraryA@4 CMP EAX,0 JE _EXIT MOV HLIB,EAX ; получить адрес процедуры-фильтра PUSH OFFSET NAMEPROC PUSH HLIB CALL GetProcAddress@8 CMP EAX,0 JE _EXIT MOV APROC,EAX ; получить адрес вспомогательной процедуры PUSH OFFSET NAMEPROC1 PUSH HLIB CALL GetProcAddress@8 CMP EAX,0 JE _EXIT MOV ATOH,EAX ; здесь установить HOOK PUSH 0 PUSH HLIB PUSH APROC PUSH WH_KEYBOARD CALL SetWindowsHookExA@16 MOV HH,EAX ; запомним и передадим в библиотеку MOV EAX,ATOH PUSH HH CALL ATOH ; открыть диалоговое окно PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 ; удалить HOOK PUSH HH CALL UnhookWindowsHookEx@4 ; закрыть библиотеку ; библиотека автоматически закрывается также ; при выходе из программы PUSH OFFSET NAMEPROC PUSH HLIB CALL FreeLibrary@4 ; выход _EXIT: PUSH 0 CALL ExitProcess@4 ; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10Н] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP,ESP PUSH EBX PUSH ESI PUSH EDI ;------------------ CMP DWORD PTR [EBP+0CH],WM_CLOSE JNE L1 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH],WM_INITDIALOG JNE FINISH FINISH: POP EDI POP ESI POP EBX POP EBP MOV EAX,0 RET 16 WNDPROC ENDP _TEXT ENDS END START ; динамическая библиотека DLL2.ASM ; содержащая процедуру-фильтр .386P ; плоская модель IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF PUBLIC HOOK, TOH ; константы ; сообщения, приходящие при открытии ; динамической библиотеки DLL_PROCESS_DETACH equ 0 DLL_PROCESS_ATTACH equ 1 DLL_THREAD_ATTACH equ 2 DLL_THREAD_DETACH equ 3 IFDEF MASM ; MASM ; прототипы внешних процедур EXTERN CallNextHookEx@16:NEAR EXTERN MessageBoxA@16:NEAR ; директивы компоновщику для подключения библиотек includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; TASM EXTERN CallNextHookEx:NEAR EXTERN MessageBoxA:NEAR CallNextHookEx@16 = CallNextHookEx MessageBoxA@16 = MessageBoxA includelib c:\tasm32\lib\import32.lib ENDIF ;-------------------------------------------------- ; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' HDL DD ? HHOOK DD ? CAP DB "Сообщение фильтра",0 MES DB "Нажат пробел",0 _DATA ENDS ; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' ; [EBP+10H] ; резервный параметр ; [EBP+0CH] ; причина вызова ; [EBP+8] ; идентификатор DLL-модуля DLLENTRY: MOV EAX,DWORD PTR [EBP+0CH] CMP EAX,0 JNE D1 ; закрытие библиотеки JMP _ЕХIТ D1: CMP EAX,1 JNE _EXIT ; открытие библиотеки ; запомнить идентификатор динамической библиотеки MOV EDX,DWORD PTR [EBP+08H] MOV HDL,EDX _ЕХIТ: MOV EAX,1 RET 12 ;---------------- TOH PROC EXPORT PUSH EBP MOV EBP,ESP MOV EAX,DWORD PTR [EBP+08H] MOV HHOOK,EAX POP EBP RET TOH ENDP ; процедура фильтра HOOK PROC EXPORT PUSH EBP MOV EBP,ESP ; отправить сообщение по цепочке PUSH DWORD PTR [EBP+010H] PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+08H] PUSH HHOOK CALL CallNextHookEx@16 ; проверить, не нажат ли пробел CMP DWORD PTR [EBP+0CH],32 JNE _EX ; нажат - выводим сообщение PUSH 0 ; МВ_ОК PUSH OFFSET CAP PUSH OFFSET MES PUSH 0 ; в окне экрана CALL MessageBoxA@16 _EX: POP EBP RET HOOK ENDP _TEXT ENDS END DLLENTRY