Воскресенье, 20.07.2025, 03:02 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 6. Некоторые вопросы системного программирования в Windows(3)

Puc. 3.6.4. Пример программы с выделением динамической памяти.

Трансляция программы на Рис. 3.6.4.
MASM32:

 ML /С /coff /DMASM MEM.ASM
 LINK /SUBSYSTEM:CONSOLE MEM.OBJ
TASM32:
 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. В первом случае блок (или его часть) перестает быть отображаемым. Во втором случае весь блок перестает быть зарезервированным. При этом значении второй параметр обязательно должен быть равен нулю.

IV

Фильтры (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


Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0