Алекс Jenter - Программирование на Visual C++. Архив рассылки

Программирование на Visual C++. Архив рассылки читать книгу онлайн
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 значительно улучшило производительность.
UnhookWindowsHookExДля удаления функции-фильтра из очереди хука вызовите функцию UnhookWindowsHookEx. Эта функция принимает хэндл хука, полученный от SetWindowsHookEx и возвращает логическое значение, показывающее успех операции. На данный момент UnhookWindowsHookEx всегда возвращает TRUE.
Фильтрующие функцииФильтрующие (хуковые) функции – это функции, прикрепленные к хуку. Из-за того, что эти функции вызываются Windows, а не приложением, их часто называют функциями обратного вызова (callback functions). Из соображений целостности изложения, эта статья использует термин фильтрующие функции (или функции-фильтры).
Все фильтрующие функции должны быть описаны следующим образом:
LRESULT CALLBACK FilterFunc(int nCode, WPARAM wParam, LPARAM lParam)
Все функции-фильтры должны возвращать LONG. Вместо FilterFunc должно стоять имя вашей фильтрующей функции.
ПараметрыФильтрующие функции принимают три параметра: nCode (код хука), wParam, и lParam. Код хука – это целое значение, которое передает функции дополнительную информацию. К примеру, код хука может описывать событие, которое привело к срабатыванию хука.
В первых версиях Windows (до 3.1), код хука указывал, должна функция-фильтр обработать событие сама или вызвать DefHookProc. Если код хука меньше нуля, фильтр не должен был обрабатывать событие, а должен был вызвать DefHookProc, передавая ей три своих параметра без изменений. Windows использовала отрицательные коды для организации цепочки функций-фильтров с помощью приложений.
Windows 3.1 также требует при отрицательном коде хука вызывать CallNextHookEx с неизмененными параметрами, плюс к тому функция должна вернуть значение, которое вернет CallNextHookEx. Но Windows 3.1 никогда не посылает фильтрующим функциям отрицательных кодов.
Второй параметр функции-фильтра, wParam, имеет тип WPARAM, и третий параметр, lParam, имеет тип LPARAM. Эти параметры передают информацию фильтрующим функциям. У каждого хука значения wParam и lParam различаются. Например, фильтры хука WH_KEYBOARD получают в wParam виртуальный код клавиши, а в lParam – состояние клавиатуры на момент нажатия клавиши. Фильтрующие функции, прикрепленные к хуку WH_MSGFILTER получают в wParam значение NULL, а в lParam – указатель на структуру, описывающую сообщение. За полным описанием значений аргументов каждого типа хука обратитесь к Win32 SDK for Windows NT, руководствуясь списком фильтрующих функций, приведенным ниже.
Хук Имя статьи с описанием фильтрующей функции в SDK WH_CALLWNDPROC CallWndProc WH_CBT CBTProc WH_DEBUG DebugProc WH_GETMESSAGE GetMsgProc WH_JOURNALRECORD JournalRecordProc WH_JOURNALPLAYBACK JournalPlaybackProc WH_SHELL ShellProc WH_KEYBOARD KeyboardProc WH_MOUSE MouseProc WH_MSGFILTER MessageProc WH_SYSMSGFILTER SysMsgProc Вызов следующей функции в цепочке фильтрующих функцийКогда хук уже установлен, Windows вызывает первую функцию в очереди, и на этом ее ответственность заканчивается. После этого функция ответственна за то, чтобы вызвать следующую функцию в цепочке. В Windows имеется функция CallNextHookEx для вызова следующего фильтра в очереди фильтров. CallNextHookEx принимает четыре параметра.
Первый параметр – это значение, возвращенное функцией SetWindowsHookEx. В настоящее время Windows игнорирует это значение, но в будущем это может измениться.
Следующие три параметра – nCode, wParam, и lParam – Windows передает дальше по цепочке функций.
Windows хранит в своих внутренних структурах цепочку фильтрующих функций и следит за тем, какая функция вызывается в настоящий момент. При вызове CallNextHookEx windows определяет следующую функцию в очереди и вызывает ее.
Иногда функции-фильтры могут не пожелать передать обработку события другим фильтрам в той же цепочке. В частности, когда хук позволяет функции отменить событие и функция решает так поступить, она не должна вызывать CallNextHookEx. Когда фильтрующая функция модифицирует сообщение, она может решить не передавать его остальным функциям, ожидающим в очереди.
Из-за того, что фильтры никак не сортируются при помещении их в очередь, вы не можете быть уверены, где находится ваша функция в любой момент времени кроме момента установки, когда ваша функция помещается в самое начало очереди. В результате, вы никогда не можете точно знать, что каждое событие в системе дойдет до вашего фильтра. Фильтрующая функция перед вашей функцией в цепочке – то есть функция, которая была установлена позже вашей – может не передать вам обработку события.
Фильтры в 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