Хуки (hooks)


Справочная система к Borland C++ 5.02 (только раздел о Win API), перевод Трубецкого А.
Этот раздел сайта постоянно обновляется (по мере появления новых переводов)
На главную

Хуки
Цепочки хуков
Функция хука
Хуки WH_CALLWNDPROC и WH_CALLWNDPROCRET
Хук WH_CBT
Хук WH_DEBUG
Хук WH_FOREGROUNDIDLE
Хук WH_GETMESSAGE
Хук WH_JOURNALPLAYBACK
Хук WH_JOURNALRECORD
Хук WH_KEYBOARD
Хук WH_MOUSE
Хуки WH_MSGFILTER и WH_SYSMSGFILTER
Хук WH_SHELL
Пример программы, ставящей хук WH_KEYBOARD


1. Хуки
Хук (hook; этот термин также часто переводят как "ловушка" или "фильтр") - это точка в механизме, обрабатывающем сообщения. В этой точке приложение может установить подпрограмму, чтобы контролировать передачу сообщений в системе и обрабатывать определенные типы сообщений прежде, чем их получит приложение, для которого они предназначены.

Хуки несколько замедляют работу системы, поскольку они увеличивают количество действий, которые производит система при обработке каждого сообщения. В связи с этим следует устанавливать хуки только при необходимости и удалять их, как только они становятся не нужны.


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, которая содержит информацию о сообщении:

typedef struct tagCWPSTRUCT {
LPARAM lParam;
WPARAM wParam;
UINT message;
HWND hwnd;
} 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. Структура содержит значение, которое возвращает функция окна, обработавшая сообщение, а также параметры сообщения:

typedef struct tagCWPRETSTRUCT {
LRESULT lResult;
LPARAM lParam;
WPARAM wParam;
DWORD message;
HWND hwnd;
} 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
Скачать исходники программы



Полезные статьи про хуки:

http://www.rsdn.ru/article/baseserv/winhooks.xml

http://www.rsdn.ru/article/baseserv/HookTools.xml


На главную

SpyLOG Rambler's Top100
Хостинг от uCoz