Идентификатор потока, для которого устанавливается хук. Если этот идентификатор ненулевой, установленная фильтрующая функция будет вызываться только в контексте указанного потока. Если идентификатор равен нулю, установленная функция имеет системную область видимости и может быть вызвана в контексте любого потока в системе. Приложение или библиотека могут использовать функцию GetCurrentThreadId для получения идентификатора текущего потока.
Некоторые хуки могут быть установлены только с системной областью видимости, некоторые можно устанавливать как для всей системы, так и для одного потока, как показано в следующей таблице.
Хук |
Область видимости |
WH_CALLWNDPROC |
Поток или вся система |
WH_CBT |
Поток или вся система |
WH_DEBUG |
Поток или вся система |
WH_GETMESSAGE |
Поток или вся система |
WH_JOURNALRECORD |
Только система |
WH_JOURNALPLAYBACK |
Только система |
WH_FOREGROUNDIDLE |
Поток или вся система |
WH_SHELL |
Поток или вся система |
WH_KEYBOARD |
Поток или вся система |
WH_MOUSE |
Поток или вся система |
WH_MSGFILTER |
Поток или вся система |
WH_SYSMSGFILTER |
Только система |
Для любого данного типа хука, первыми вызываются хуки потоков, и только затем системные хуки.
Есть несколько причин, по которым лучше использовать потоковые хуки вместо системных. Хуки потоков:
• Не создают лишней работы приложениям, которые не заинтересованы в вызове хука.
• Не помещают все события, относящиеся к хуку, в очередь (так, чтобы они поступали не одновременно, а одно за другим). Например, если приложение установит клавиатурный хук для всей системы, то все клавиатурные сообщения будут пропущены через фильтрующую функцию этого хука, оставляя неиспользованными системные возможности многопотоковой обработки ввода. Если эта функция прекратит обрабатывать клавиатурные события, система будет выглядеть зависшей, хотя на самом деле и не зависнет. Пользователь всегда сможет использовать комбинацию CTRL+ALT+DEL для того, чтобы выйти из системы (log-out) и решить проблему, но ему это вряд ли понравится. К тому же, пользователь может не знать, что подобную ситуацию можно решить, войдя в систему под другим именем (log-out/log-in).
• Не требуют нахождения функции-фильтра в отдельной DLL. Все системные хуки и хуки для потоков в другом приложении должны находиться в DLL.
• Им не нужно разделять данные между DLL, загруженными в разные процессы. Фильтрующие функции с системной областью видимости, которые обязаны находиться в DLL, должны к тому же разделять необходимые данные с другими процессами. Так как такое поведение не является типичным для DLL, вы должны принимать специальные меры предосторожности при реализации системных фильтрующих функций. Если функция-фильтр не умеет разделять данные и неправильно использует данные в другом процессе, этот процесс может рухнуть.
SetWindowsHookExвозвращает хэндл установленного хука (тип hhook). Приложение или библиотека должны использовать этот хэндл для вызова функции UnhookWindowsHookEx. SetWindowsHookExвозвращает null если она не смогла добавить функцию к хуку. SetWindowsHookExтакже устанавливает код последней ошибки в одно из следующих значений для индикации неудачного завершения функции.
• ERROR_INVALID_HOOK_FILTER: Неверный код хука.
• ERROR_INVALID_FILTER_PROC: Неверная фильтрующая функция.
• ERROR_HOOK_NEEDS_HMOD: Глобальный хук устанавливается с параметром hInstance , равным NULL либо локальный хук устанавливается для потока, который не принадлежит данному приложению.
• ERROR_GLOBAL_ONLY_HOOK: Хук, который может быть только системным, устанавливается как потоковый.
• ERROR_INVALID_PARAMETER: Неверный идентификатор потока.
• ERROR_JOURNAL_HOOK_SET: Для регистрационного хука (journal hook) уже установлена фильтрующая функция. В любой момент времени может быть установлен только один записывающий или воспроизводящий хук. Этот код ошибки может также означать, что приложение пытается установить регистрационный хук в то время, как запущен хранитель экрана.
• ERROR_MOD_NOT_FOUND: Параметр hInstance в случае, когда хук является глобальным, не ссылался на библиотеку. (На самом деле, это значение означает лишь, что модуль User не смог обнаружить данный хэндл в списке модулей.)
• Любое другое значение: Система безопасности не позволяет установить данный хук, либо в системе закончилась память.
Windows сама заботится об организации очереди функций-фильтров (см. рисунок ниже), не доверяя функциям хранение адресов следующих функций в очереди (как поступали Windows до версии 3.1). Таким образом, система хуков в Windows 3.1 и более поздних версий стала гораздо яснее. Плюс к тому, факт хранения цепочки функций-фильтров внутри Windows значительно улучшило производительность.
Читать дальше