Фильтры в DLL
Фильтрующие функции с системной областью видимости должны быть реализованы в DLL. В Win16 было возможно (хотя и не рекомендовалось) установить системный хук, находящийся в приложении. Это не сработает в Win32. Ни в коем случае не устанавливайте глобальных фильтров, не находящихся в отдельной DLL, даже если это где-нибудь и работает. Регистрационные хуки, WH_JOURNALRECORD и WH_JOURNALPLAYBACK, являются исключением из правила. Из-за того, как Windows вызывает эти хуки, их фильтрующим функциям не обязательно находиться в DLL.
Фильтрующие функции для хуков с системной областью видимости должны быть готовы разделять свои данные между разными процессами, из которых они запускаются. Каждая DLL отображается в адресное пространство использующего ее клиентского процесса. Глобальные переменные в DLL будут таковыми лишь в пределах одного экземпляра приложения, если только они не будут находиться в разделяемом сегменте данных (shared data section). Например, библиотека HOOKSDLL.DLL в примере Hooks использует две глобальные переменные:
• Хэндл окна для отображения сообщений.
• Высоту строк текста в этом окне.
Для того, чтобы сделать эти данные общими для всех экземпляров библиотеки, HOOKSDLL помещает их в разделяемый сегмент данных. Для этого HOOKSDLL предпринимает следующие шаги:
• Использует директивы компилятора (pragma) для помещения данных в именованный сегмент данных. Заметьте, что при этом переменные должны быть обязательно инициализированы.
// Shared DATA
#pragma data_seg(".SHARDATA")
static HWND hwndMain = NULL; // Главный hwnd. Мы получим его от приложения.
static int nLineHeight = 0; // Высота строк в окне.
#pragma data_seg()
Добавляет блок SECTIONS в .DEF-файл библиотеки:
SECTIONS
.SHARDATA Read Write Shared
Создает .EXP-файл из .DEF-файла:
hooksdll.exp: hooksdll.obj hooksdll.def
$(implib) –machine:$(CPU) \
–def:hooks.def \
hooksdll.obj \
–out:hooksdll.lib
Прилинковывает получившийся файл HOOKSDLL.EXP:
hooksdll.dll: hooksdll.obj hooksdll.def hooksdll.lib hooksdll.exp
$(link) $(linkdebug) \
–base:0x1C000000 \
–dll \
–entry:LibMain$(DLLENTRY) \
–out:hooksdll.dll \
hooksdll.exp hooksdll.obj hooksdll.rbj \
$(guilibsdll)
Типы хуков
WH_CALLWNDPROC
Windows вызывает этот хук при каждом вызове функции SendMessage. Фильтрующей функции передается код хука, показывающий, была ли произведена посылка сообщения из текущего потока, а также указатель на структуру с информацией о сообщении.
Структура CWPSTRUCT описана следующим образом:
typedef struct tagCWPSTRUCT {
LPARAM lParam;
WPARAM wParam;
DWORD message;
HWND hwnd;
} CWPSTRUCT, *PCWPSTRUCT, NEAR *NPCWPSTRUCT, FAR *LPCWPSTRUCT;
Фильтры могут обработать сообщение, но не могут изменять его (хотя это было возможно в Win16). Сообщение затем отсылается той функции, которой и предназначалось. Этот хук использует значительное количество системных ресурсов, особенно, когда он установлен с системной областью видимости, поэтому используйте его только в целях отладки.
WH_CBT
Чтобы написать приложение для интерактивного обучения (CBT application), разработчик должен координировать его работу с работой приложения, для которого оно разрабатывается. Для достижения этой цели Windows предоставляет разработчикам хук WH_CBT. Windows передает фильтрующей функции код хука, показывающий, какое произошло событие, и соответствующие этому событию данные.
Фильтр для хука WH_CBT должен знать о десяти хуковых кодах:
• HCBT_ACTIVATE
• HCBT_CREATEWND
• HCBT_DESTROYWND
• HCBT_MINMAX
• HCBT_MOVESIZE
• HCBT_SYSCOMMAND
• HCBT_CLICKSKIPPED
• HCBT_KEYSKIPPED
• HCBT_SETFOCUS
• HCBT_QS
HCBT_ACTIVATE
Windows вызывает хук WH_CBT с этим кодом при активации какого-нибудь окна. Когда хук WH_CBT установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если фильтр в ответ на это событие вернет TRUE, окно не будет активизировано.
Параметр wParam содержит хэндл активизируемого окна. В lParam содержится указатель на структуру CBTACTIVATESTRUCT, которая описана следующим образом:
typedef struct tagCBTACTIVATESTRUCT {
BOOL fMouse; // TRUE, если активация наступила в результате
// мышиного клика; иначе FALSE.
HWND hWndActive; // Содержит хэндл окна, активного
// в настоящий момент.
} CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;
HCBT_CREATEWND
Windows вызывает хук WH_CBT с этим при создании окна. Когда хук установлен как локальный, это окно должно создаваться потоком, на который установлен хук. Хук WH_CBT вызывается до того, как Windows пошлет новому окну сообщения WM_GETMINMAXINFO, WM_NCCREATE, или WM_CREATE. Таким образом, фильтрующая функция может запретить создание окна, вернув TRUE.
Читать дальше