Хуки несколько замедляют работу системы, поскольку они увеличивают
количество действий, которые производит система при обработке каждого
сообщения. В связи с этим следует устанавливать хуки только при
необходимости и удалять их, как только они становятся не нужны.
2.
Цепочки хуков
Windows содержит много различных типов хуков; они обеспечивают доступ к
различным аспектам механизма, обрабатывающего сообщения. Например, хук
WH_MOUSE позволяет контролировать передачу сообщений от мыши.
Windows позволяет строить цепочки из однотипных хуков. Цепочка хуков
(hook chain) - это список указателей на определенные приложением
функции
обратного вызова, которые вызывают функции хука
(hook procedures). Когда появляется сообщение, связанное с типом
установленного хука, Windows передает это сообщение по очереди каждой
функции хука, упомянутой в цепочке. Действие, которое может совершить
функция хука, зависит от типа данного хука. Функции для некоторых типов
хуков могут только просматривать сообщения; другие функции могут
изменять сообщения или останавливать их продвижение по цепочке, не
позволяя им достигнуть следующей функции хука или окна-адресата.
3.
Функция хука
Для того, чтобы использовать определенный тип хука, программист создает
функцию хука. Затем с помощью функции SetWindowsHookEx() устанавливает созданную функцию
хука в цепочку, связанную с данным хуком. Функция хука должна иметь
следующий синтаксис:
LRESULT CALLBACK HookProc(
int
nCode,
WPARAM wParam,
LPARAM lParam)
Вместо HookProc следует подставить имя функции хука,
определенное приложением.
Параметр nCode - код хука. Функция хука использует его, чтобы
определить действие, которое необходимо исполнить. Значение кода хука
зависит от типа хука; каждый тип имеет свой набор кодов хука.
Значения параметров wParam и lParam зависят от кода
хука,
но обычно они содержат информацию об отправленном сообщении.
Функция SetWindowsHookEx()
всегда устанавливает функцию хука в начало цепочки хуков. Когда
происходит событие, которое отслеживается данным типом хука, Windows
вызывает функцию, которая находится в начале цепочки, связанной с этим
хуком. Каждая функция хука в цепочке решает, передавать ли событие
следующей функции. Функция хука может передать событие следующей
функции, используя функцию CallNextHookEx().
Обратите внимание, что функции хука для некоторых типов хуков могут
только просматривать сообщения. Windows передает сообщения к каждой
функции хука такого типа даже в том случае, если функции хука не
используют функцию CallNextHookEx().
Функция хука может быть глобальной. В этом случае она просматривает
сообщения для всех потоков в системе. Можно также определить функцию
хука для одного потока, чтобы просматривать сообщения, предназначенные
только этому потоку. Глобальная функция хука может быть вызвана в
контексте любого приложения, поэтому она должна быть помещена в
отдельный модуль библиотеки DLL. Функция хука, определенная для одного
потока, вызывается только в контексте данного потока. Если приложение
устанавливает функцию хука для одного из своих собственных потоков, она
может находиться или в том же модуле, что и остальная часть кода
приложения, или в DLL. Если приложение устанавливает функцию хука для
потока другого приложения, ее надо поместить в DLL.
Примечание: Использовать глобальные хуки следует только в целях
отладки, в противном случае лучше избегать их. Глобальные хуки снижают
эффективность системы и вызывают конфликты с другими приложениями,
которые используют такой же тип глобального хука.
4. Типы хуков:
Хуки WH_CALLWNDPROC и WH_CALLWNDPROCRET
Хуки WH_CALLWNDPROC и WH_CALLWNDPROCRET позволяют контролировать
сообщения, посланные функциям окна приложений функцией SendMessage(). Windows
вызывает функцию хука WH_CALLWNDPROC прежде, чем функция окна получит
предназначенное ей сообщение. Функция хука WH_CALLWNDPROCRET вызывается
после того, как функция окна получит и обработает сообщение.
Прототип функции хука WH_CALLWNDPROC:
LRESULT CALLBACK CallWndProc( int nCode, // код хука WPARAM wParam, LPARAM lParam );
Параметр wParam - флаг, который определяет, было ли сообщение
отправлено текущим процессом. Если сообщение отправлено текущим
процессом, флаг имеет ненулевое значение. В противном случае значение
флага равно NULL.
Параметр lParam - указатель на структуру CWPSTRUCT, которая
содержит информацию о сообщении:
Поля структуры: lParam - содержит дополнительную информацию о сообщении. Точное
значение зависит от параметра message. wParam - содержит дополнительную информацию о сообщении. Точное
значение зависит от параметра message. message - определяет сообщение. hwnd - идентификатор окна, которое получило сообщение,
определенное параметром message.
Прототип функции хука WH_CALLWNDPROCRET:
//функция не поддерживается Windows NT ! LRESULT CALLBACK CallWndRetProc( int nCode, // код хука WPARAM wParam, LPARAM lParam );
Параметр wParam - флаг, который определяет, было ли сообщение
отправлено текущим процессом. Если сообщение отправлено текущим
процессом, флаг имеет ненулевое значение. В противном случае значение
флага равно NULL.
Параметр lParam - указатель на структуру CWPRETSTRUCT, которая
содержит информацию о сообщении.
Хук WH_CALLWNDPROCRET передает функции хука адрес структуры
CWPRETSTRUCT. Структура содержит значение, которое возвращает функция
окна, обработавшая сообщение, а также параметры сообщения:
Поля структуры: lResult - возвращаемое значение функции окна, которая обработала
сообщение, определенное параметром message. lParam - содержит дополнительную информацию о сообщении. Точное
значение зависит от параметра message. wParam - содержит дополнительную информацию о сообщении. Точное
значение зависит от параметра message. message - определяет сообщение. hwnd - идентификатор окна, которое обработало сообщение,
определенное параметром message.
Хук WH_CBT
Windows вызывает функцию хука WH_CBT в следующих случаях:
1. перед активизацией, созданием, разрушением, сворачиванием,
разворачиванием, перемещением или изменением размеров окна;
2. перед завершением системной команды;
3. перед удалением события, связанного с мышью или клавиатурой, из
системной очереди сообщений;
4. перед установкой фокуса ввода;
5. перед синхронизацией посредством системной очереди сообщений
(synchronizing with the system message queue).
Значение, которое возвращает функция хука, определяет, будет ли
разрешена соврешенная операция. Хук WH_CBT предназначен прежде всего
для
обучающих приложений (computer-based training (CBT) applications).
Прототип функции хука:
LRESULT CALLBACK CBTProc( int nCode, // код хука WPARAM wParam, // зависит от кода хука LPARAM lParam // зависит от кода хука );
Параметр nCode может принимать
следующие значения:
HCBT_ACTIVATE
Система собирается
активизировать окно.
HCBT_CLICKSKIPPED
Система удалила сообщение от
мыши из системной очереди сообщений. Получив этот код хука,
CBT-приложение должно установить функцию хука WH_JOURNALPLAYBACK, если
нужно ответить на это сообщение от мыши. С помощью хука
WH_JOURNALPLAYBACK можно вернуть сообщение от мыши в очередь сообщений.
HCBT_CREATEWND
Система собирается создать окно.
Система вызывает функцию хука перед тем, как послать окну сообщение
WM_CREATE или WM_NCCREATE. Если функция хука возвращает ненулевое
значение, система уничтожает окно; функция CreateWindow() возвращает
NULL, но сообщение WM_DESTROY окну не посылается. Если функция хука
возвращает 0, окно создается в обычном режиме.
В момент получения сообщения HCBT_CREATEWND окно уже создано, но его
размер, расположение и родительское окно еще не заданы. Вы можете
послать сообщение созданному окну, хотя оно еще не получило сообщение
WM_NCCREATE или WM_CREATE. Вы также можете изменить положение
созданного
окна в Z-последовательности, определив поле hwndInsertAfter структуры
CBT_CREATEWND.
HCBT_DESTROYWND
Система собирается уничтожить
окно.
HCBT_KEYSKIPPED
Система удалила сообщение от
клавиатуры из системной очереди сообщений. Получив сообщение этого
типа,
CBT-приложение должно установить функцию хука WH_JOURNALPLAYBACK, если
нужно ответить на удаленное сообщение от клавиатуры. С помощью хука
WH_JOURNALPLAYBACK можно вернуть сообщение от клавиатуры в очередь
сообщений.
HCBT_MINMAX
Система собирается свернуть или
развернуть окно.
HCBT_MOVESIZE
Система собирается переместить
окно или изменить его размер.
HCBT_QS
Система извлекла сообщение
WM_QUEUESYNC из очереди сообщений.
HCBT_SETFOCUS
Система собирается передать окну
фокус ввода.
HCBT_SYSCOMMAND
Система собирается выполнить
системную команду. Перехват этого сообщения позволяет CBT-приложению
запретить переключение задач с помощью горячих клавиш.
Если параметр nCode меньше
нуля, функция хука просто передает сообщение функции CallNextHookEx() без
дальнейшей обработки и возвращает значение, возвращаемое функцией CallNextHookEx().
Возвращаемое значение
Для операций, о которых сигнализируют сообщения перечисленных ниже
типов, возвращаемое значение должно быть равно нулю, если системе
позволяется выполнить данную операцию, или 1, если запрещается:
HCBT_ACTIVATE
HCBT_CREATEWND
HCBT_DESTROYWND
HCBT_MINMAX
HCBT_MOVESIZE
HCBT_SETFOCUS
HCBT_SYSCOMMAND
Для операций, о которых сигнализируют сообщения перечисленных ниже
типов, возвращаемое значение игнорируется:
HCBT_CLICKSKIPPED
HCBT_KEYSKIPPED
HCBT_QS
Хук
WH_DEBUG
Windows вызывает функцию хука WH_DEBUG перед вызовом функции любого
другого хука, установленного в системе. Таким образом, этот хук можно
использовать для того, чтобы запретить системе вызывать функции других
хуков.
Прототип функции хука:
LRESULT CALLBACK DebugProc( int nCode, // код хука WPARAM wParam, // тип хука, функция которого будет вызвана, // если DebugProc() не запретит вызов LPARAM lParam // указатель на структуру DEBUGHOOKINFO );
Параметр nCode указывает,
должна ли функция хука обработать сообщение. Если параметр nCode равен HC_ACTION, то функция
хука должна обработать данное сообщение. Если nCode меньше нуля, то функция хука
должна передать сообщение функции CallNextHookEx(), не обрабатывая его, и должна
вернуть значение, которое вернет функция CallNextHookEx().
Параметр wParam указывает,
какой тип хука собирается вызвать система. Этот параметр может
принимать
следующие значения: WH_CALLWNDPROC, WH_CALLWNDPROCRET, WH_CBT,
WH_DEBUG,
WH_GETMESSAGE, WH_JOURNALPLAYBACK, WH_JOURNALRECORD, WH_KEYBOARD,
WH_MOUSE, WH_MSGFILTER, WH_SHELL, WH_SYSMSGFILTER.
Параметр lParam указывает на
структуру DEBUGHOOKINFO, содержащую параметры, которые будут переданы
функции вызываемого хука.
Возвращаемое значение
Чтобы запретить системе вызывать хук, функция должна вернуть ненулевое
значение. В противном случае функция должна передать информацию о хуке
функции CallNextHookEx().
Хук
WH_FOREGROUNDIDLE
Хук WH_FOREGROUNDIDLE позволяет выполнять фоновые задачи, когда поток,
на который установлен хук, не используется. Функция этого хука
вызывается, когда система собирается сделать основной поток приложения
неактивным.
Хук
WH_GETMESSAGE
Этот хук позволяет приложению контролировать сообщения, которые функция
GetMessage() или PeekMessage() собирается
извлечь из очереди сообщений. Хук WH_GETMESSAGE можно использовать для
просмотра сообщений, полученных от мыши или клавиатуры, а также других
сообщений, помещаемых в очередь сообщений.
Хук
WH_JOURNALPLAYBACK
Хук WH_JOURNALPLAYBACK позволяет приложению помещать сообщения в
системную очередь сообщений. Этот хук можно использовать для того,
чтобы
проигрывать серию событий от мыши или клавиатуры, которая прежде была
записана с помощью хука WH_JOURNALRECORD. Если этот хук установлен,
нормальный ввод от мыши и клавиатуры блокируется до тех пор, пока хук
не
будет снят. Хук WH_JOURNALPLAYBACK может быть только глобальным, т.е.
его нельзя установить для отдельного потока.
Хук WH_JOURNALPLAYBACK возвращает время ожидания (time-out value). Это
значение сообщает системе, сколько миллисекунд нужно подождать прежде
чем обработать данное сообщение из серии событий. Таким образом, хук
может контролировать периодичность проигрываемых событий.
Хук
WH_JOURNALRECORD
Хук WH_JOURNALRECORD позволяет контролировать и создавать события ввода
(input events). Обычно этот хук используется для записи
последовательности событий от мыши и клавиатуры, чтобы позднее
проиграть
их с помощью хука WH_JOURNALPLAYBACK. Хук WH_JOURNALRECORD является
глобальным и не может быть установлен для отдельного потока.
Хук
WH_KEYBOARD
Windows вызывает функцию этого хука, когда функция GetMessage() или PeekMessage() собирается
извлечь из системной очереди сообщение WM_KEYDOWN или WM_KEYUP. Данный
хук можно использовать для отслеживания сообщений от клавиатуры,
которые
помещаются в системную очередь сообщений.
Хук
WH_MOUSE
Windows вызывает функцию этого хука, когда функция GetMessage() или PeekMessage() собирается
извлечь из системной очереди сообщение от мыши. Данный хук можно
использовать для отслеживания сообщений от мыши, которые помещаются в
системную очередь сообщений.
Хуки
WH_MSGFILTER и WH_SYSMSGFILTER
Хуки WH_MSGFILTER и WH_SYSMSGFILTER позволяют перехватывать сообщения,
предназначенные для меню, полос прокрутки, окон сообщений (message
box),
диалоговых окон. Эти хуки также позволяют определять, когда система
собирается активировать другое окно в результате нажатия пользователем
клавиш ALT+TAB or ALT+ESC. Хук WH_MSGFILTER может контролировать только
сообщения для меню, полос прокрутки окон сообщений и диалоговых окон,
созданных самим приложением, установившим хук. Хук WH_SYSMSGFILTER
контролирует подобные сообщения для всех приложений.
Хук
WH_SHELL
Windows вызывает функцию хука WH_SHELL, когда система собирается
активировать оболочку приложения, а также перед созданием или
уничтожением окна верхнего уровня (top-level window).
Вы можете скачать пример программы, ставящей хук
WH_KEYBOARD. Хук ставится глобальный, поэтому код функции хука
находится
в *.dll, которая собирается в отдельном проекте, а потом копируется в
папку
к управляющему приложению hook_man.exe Скачать
исходники программы