Что такое код unhookwindowshook

Содержание

Win32 API. Hooks (хуки)
Страница 5. Функция CallNextHookEx

Функция CallNextHookEx

Функция CallNextHookEx передает информацию hook-точки в следующую подключаемую процедуру в текущей цепочке hook-точек. Эта функция заменяет функцию DefHookProc.

Параметры
hhk
Идентифицирует текущую hook-точку. Прикладная программа принимает этот дескриптор в результате предыдущего вызова функции SetWindowsHookEx.
nCode
Определяет код hook-точки, переданный в текущую подключаемую процедуру. Следующая фильтр — процедура использует этот код, чтобы определить, как обрабатывать информацию hook-точки.
wParam
Определяет значение wParam, переданное в текущую подключаемую процедуру. Значение этого параметра зависит от типа hook-точки, связанной с текущей цепочкой hook-точек.
lParam
Определяет значение lParam, переданное в текущую подключаемую процедуру. Значение этого параметра зависит от типа hook-точки, связанной с текущей цепочкой hook-точек.

Возвращаемые значения
Если функция завершается успешно, возвращаемое значение — величина, возвращенная следующей подключаемой процедурой в цепочке. Текущая фильтр — процедура должна также возвратить это значение. Значение возвращаемой величины зависит от типа hook-точки. Для получения дополнительной информации смотри описания индивидуальных подключаемых процедур.

Замечания
Подключаемые процедуры устанавливаются в цепочки конкретных типов hook-точек. Функция CallNextHookEx вызывает следующую hook-точку в цепочке.
Вызов CallNextHookEx необязателен. Фильтр — процедура может вызывать эту функцию или до или после обработки информации hook-точки. Если подключаемая процедура не вызывает CallNextHookEx, Windows не вызывает Фильтр — процедуры установленные до того, как была установлена текущая подключаемая процедура.

Смотри также
SetWindowsHook, SetWindowsHookEx, UnhookWindowsHook, UnhookWindowsHookEx

Размещение и совместимость CallNextHookEx

Хуки в Windows. Часть первая. Основы

Этой статьёй я начинаю цикл статей про механизм ловушек оконных сообщений, а на жаргоне программистов механизм хуков, в операционных системах Windows. Тема про хуки является популярной на многих форумах программистов. Материал этих статей рассчитан на начинающего пользователя, примеры будут на Delphi. В этой статье будут изложены основные принципы механизма хуков, и будет написан пример клавиатурного шпиона.

Итак, приступим, что же такое механизм хуков в Windows? В операционной системе Windows хуком называется механизм перехвата особой функцией событий (таких как сообщения, ввод с мыши или клавиатуры) до того, как они дойдут до приложения. Эта функция может затем реагировать на события и, в некоторых случаях, изменять или отменять их. Функции, получающие уведомления о событиях, называются фильтрующими функциями и различаются по типам перехватываемых ими событий. Пример — фильтрующая функция для перехвата всех событий мыши или клавиатуры. Если к одному хуку прикреплено несколько фильтрующих функций, Windows реализует очередь функций, причем функция, прикрепленная последней, оказывается в начале очереди, а самая первая функция — в ее конце.

Когда к хуку прикреплена одна или более функций-фильтров и происходит событие, приводящее к срабатыванию хука, Windows вызывает только первую функцию из очереди функций-фильтров. Вызов каждого следующего обработчика полностью зависит от предыдущего обработчика. Если какой-либо обработчик не вызовет следующий, то целевому окну не придёт искомое сообщение, а следовательно и не будет вызвана его оконная функция.

Хуки предоставляют мощные возможности для приложений Windows. Приложения могут использовать хуки в следующих целях:

  • Обрабатывать или изменять все сообщения, предназначенные для всех диалоговых окон (dialog box), информационных окон (message box), полос прокрутки (scroll bar), или меню одного приложения (WH_MSGFILTER).
  • Обрабатывать или изменять все сообщения, предназначенные для всех диалоговых окон, информационных окон, полос прокрутки, или меню всей системы (WH_SYSMSGFILTER).
  • Обрабатывать или изменять все сообщения в системе (все виды сообщений), получаемые функциями GetMessage или PeekMessage (WH_GETMESSAGE).
  • Обрабатывать или изменять все сообщения (любого типа), посылаемые вызовом функции SendMessage (WH_CALLWNDPROC).
  • Записывать или проигрывать клавиатурные и мышиные события (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
  • Обрабатывать, изменять или удалять клавиатурные события (WH_KEYBOARD).
    Обрабатывать, изменять или отменять события мыши (WH_MOUSE).
  • Реагировать на определенные действия системы, делая возможным разработку приложений компьютерного обучения — computer-based training (WH_CBT).
  • Предотвратить вызов другой функции-фильтра (WH_DEBUG).

    Работа с хуками осуществляется через функции SetWindowsHookEx, UnhookWindowsHookEx, вызов следующего обработчика осуществляется через функцию CallNextHookEx. До версии 3.1 Windows предоставляла для управления хуками функции SetWindowsHook, UnhookWindowsHook, и DefHookProc. Эти функции до сих пор реализованы в Win32, только лишь для совместимости со старыми приложениями, и использовать их в новых проектах не рекомендуется.

    Начнём сначала, для установки хука успользуется функция SetWindowsHookEx

    Первый параметр это числовая константа WH_* которая задаёт тип устанавливаемого хука. Второй параметр это адрес функции-фильтра. Третий параметр это хэндл модуля, содержащего фильтрующую функцию. Этот параметр должен быть равен нулю при установке хука на поток, но данное требование не является строго обязательным, как указано в документации. При установке хука для всей системы или для потока в другом процессе, нужно использовать хэндл DLL, содержащей функцию-фильтр. Четвёртый параметр это идентификатор потока, для которого устанавливается хук. Если он не равен нулю, то хук устанавливается только на указанный поток. Если идентификатор равен нулю, то хук устанавливается на всю систему. Некоторые хуки можно ставить как на всю систему, так и на некоторый поток, некоторые хуки можно поставить только на всю систему. Функция возвращает хендл хука, в случае неудачи функция возвратит ноль. Для снятия хука нужно использовать функцию UnhookWindowsHookEx, которая принимает в качестве единственного параметра хендл установленного хука.

    Теперь надо сделать небольшое лирическое отступление от данной темы, для лучшего понятия описываемого механизма. В 32-битных (а далее в 64-битных) операционных системах Windows каждый процесс в системе имеет своё собственное обособленное адресное пространство. Обратиться к чужому адресному пространству можно только через несколько API функций и имея определённые привилегии. Т.е. по одному и тому же адресу в разных процессах могут быть совершенно разные данные. Для того чтобы фильтрующая функция могла обработать сообщение, она должна находиться в памяти именно того процесса, которому принадлежит целевое окно и оконная функция. Итак, если хук устанавливается на всю систему, то фильтрующая функция должна быть загружена в каждый процесс, у которого есть хотя бы один цикл сообщений c использованием функций GetMessage или PeekMessage. Единственный стандартный способ загрузки нашего кода в чужой процесс, это использование DLL. Т.е. для нормального функционирования хуков установленных на всю систему необходимо использовать DLL.

    Едем, далее. Все фильтрующие функции должны быть описаны следующим образом:

    Так написано в MSDN. Тип LRESULT это тот же integer, WPARAM и LPARAM это тоже integer. CALLBACK это тоже что и stdcall. Чтобы было понятнее, приведу наиболее правильное и логичное (по моему мнению) объявление на pascal:

    Это общий прототип функции для всех типов хуков. Параметры интерпретируются по-разному, в зависимости типа хука. Очень часто встречается одна и та же ошибка: объявление параметра wParam как WORD. Это грубая ошибка, которая приводит к непредсказуемым последствиям в работе хуков, так как тип WORD имеет размерность 16 бит, а DWORD 32 бита, в результате чего половина информации, передаваемая через этот параметр, теряется. Первый параметр во всех типах хуков интерпретируется в основном одинаково: если он меньше нуля, то надо сразу же вызвать следующую функцию через CallNextHookEx, и вернуть результат её вызова. Если код равен HC_ACTION, то можно обработать это сообщение. Впрочем, это только рекомендации и всё полностью зависит от самой функции и программиста, который её написал.

    Для вызова следующей функции в очереди хуков предназначена функция CallNextHookEx

    Отличие от оконной функции лишь в первом параметре, который, кстати, в системах семейства Windows NT (Windows NT/XP/2003 и далее) игнорируется. Для того чтобы не передавать дальше обработку сообщения, достаточно просто не вызывать эту функцию в обработчике. В данном случае это сообщение просто блокируется и не приходит адресату.

    Итак, основные сведения о хуках мы получили. Теперь надо приступить к практике. Наиболее часто встречающийся проблемы поднимаемые на форумах программистов, связанный с хуками, это проблемы с написанием клавиатурных шпионов. Именно клавиатурный шпион мы сейчас и напишем.

    Для создания клавиатурного хука нам надо указать код WH_KEYBOARD при вызове функции SetWindowsHookEx. Windows вызывает обработчики хка когда функции GetMessage или PeekMessage собираются вернуть сообщения WM_KEYUP, WM_KEYDOWN.
    Параметр Code может быть равен следующим значениям

  • HC_ACTION Windows вызывает обработчик с этим кодом при удалении сообщения из очереди.
  • HC_NOREMOVE Windows вызывает обработчик с этим кодом, когда клавиатурное сообщение не удаляется из очереди, потому что приложение вызвало функцию PeekMessage с параметром PM_NOREMOVE. При вызове хука с этим кодом не гарантируется передача действительного состояние клавиатуры. Программист должен знать о возможности возникновения подобной ситуации.

    Параметр wParam в обработчике хука WH_KEYBOARD содержит виртуальный код клавиши (например, VK_F1, VK_RETURN, VK_LEFT). Параметр lParam расшифровывается следующим образом.

  • Биты 0-15 содержат количество повторений нажатой клавиш ив случае залипания.
  • Биты 16-23 содержат скан код нажатой клавиши. Это аппаратно зависимый код, который зависит от конкретной клавиатуры.
  • Бит 24 равен единице, если нажатая клавиша является расширенной (функциональной или на цифровой клавиатуре), иначе 0.
  • Биты 25-28 зарезервированы.
  • Бит 29 выставлен, если нажата кнопка Alt.
  • Бит 30 говорит нам о состоянии клавиши до отправки сообщения. Бит равен единице если до этого кнопка до отправки сообщения нажата, если кнопка была до этого не нажата, то бит равен нулю.
  • Бит 31 говорит о текущем состоянии клавиши. Он равен нулю, если кнопка в нажатом состоянии, и единица, если в не нажатом состоянии.

    Как мы будем сохранять введённый текст? Разумеется, самый простой способ это сохранение в файл перехваченного кода нажатой клавиши это сохранение в файл сразу же в функции фильтре. Но операции файлового ввода/вывода это операции не слишком быстрые и это приводит к общему уменьшению производительности системы при вводе какого-либо текста (впрочем, на новых машинах это вряд ли можно заметить). Поэтому мы заведём специальное окно-сервер, которому будем отправлять коды нажатых клавиш, это окно будет получать коды нажатых клавиш и сохранять в своём буфере, и скидывать буфер в файл, когда он будет достигать некоторого размера.

    Создание и снятие хука, я думаю, особых проблем не составляет, поэтому сразу приступлю к самому обработчику хука.

    Основная проблема в при написании клавиатурных хуков заключается в том что обработчику хука передаётся только скан код нажатой клавиши и её виртуальный код. Виртуальный код и скан код говорят нам, какая именно клавиша была нажата, но не говорят, что именно было введено. Поясню, даже если мы вводим русский текст, то клавиатурному хуку будут передаваться коды английских клавиш, т.е. мы вводим слово «привет», а обработчику хука будет передано «GHBDTN». Или, например, мы нажимаем на Shift цифру 7 и вводится знак &, но в клавиатурный хук будт передан только код цифры 7. Для того чтобы преобразовать скан код и виртуальный код в текстовый символ, который был введён, необходимо использовать функцию ToAscii (или ToUnicode).
    Её параметры:

    Первый параметр это виртуальный код, второй это скан код, третий параметр это указатель на массив в котором сохранено состояние клавиатуры, четвёртый это указатель на переменную, в которую будет сохранён символ, пятый параметр это флаг, определяющий, является ли меню активным. Этот параметр должен быть 1, если меню активно, или иначе 0. Функция возвращает количество символов, полученных в результате преобразования. Состояние клавиатуры можно получить через функцию GetKeyboardState.

    Вернёмся в нашей фильтрующей функции.

    Сначала мы получаем состояние клавиатуры, потом получаем скан код из параметры LParam и вызываем функцию ToAscii. Если её результат не равен нулю, т.е. если её результат не пустой, то отправляем cсообщение окну-серверу с заголовком «Simple keylogger » (цифры в заголовке нужны только лишь для его уникальности). Сообщение WM_KEYEVENT мы объявили сами

    А вот собственно и сам обработчик сообщения WM_KEYEVENT

    Для получения текстовой расшифровки нажатой клавиши по её скан коду мы воспользовались функцией GetKeyNameText. Полный текст DLL и приложения находится в архиве прилагающемуся к этой статье.

    Если посмотреть получившийся лог, то мы увидим следующий текст в формате .

    Вот и подошёл конец первой статьи про хуки. Качаем, смотрим исходник исследуем, учимся.

    Qt WinAPI — Урок 009. SetWindowsHookEx — Логирование событий мыши через WinAPI

    Функционал WinAPI позволяет на низком уровне с помощью хуков отслеживать события системы, такие как движение и клики мыши. Данный функционал работает на основе функций callback, поэтому если хочется использовать ООП и систему сигналов и слотов , то нужно будет один из методов передавать в качестве функции callback в функцию по регистрации callback в системе Windows. Но метод должен быть статическим, поэтому требуется разрабатывать класс в качестве Синглтона.

    SetWindowsHookEx

    Данная функция используется для регистрации функции-обработчика событий в цепочке hook-обработчиков для отслеживания некоторых событий в системе Windows

    Параметры

    Тип: int

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

    • WH_CALLWNDPROC — Устанавливает hook процедуру, которая отслеживает сообщения до того, как система перешлёт их в обработку окну назначения.
    • WH_CALLWNDPROCRET — Устанавливает hook процедуру, которая отслеживает сообщения после того, как они были обработаны окном назначения.
    • WH_CBT — Устанавливает hook процедуру, которая принимает полезные уведомления для прикладной программы.
    • WH_DEBUG — устанавливает hook процедуру, которая полезна при отладке других hook процедур.
    • WH_FOREGROUNDIDLE — Устанавливает hook процедуру, которая будет вызываться в том случае, когда приложение простаивает. Может быть полезно для выполнения задач с низким приоритетом во время простоя.
    • WH_GETMESSAGE — устанавливает hook процедуру, которая контролирует сообщения, отправленные в очередь сообщений.
    • WH_JOURNALPLAYBACK — устанавливает hook процедуру, вызывающую сообщения, ранее записанные с помощью процедуры WH_JOURNALRECORD.
    • WH_JOURNALRECORD — устанавливает hook процедуру, которая записывает входные сообщения, отправленные в системную очередь сообщений. Данный hook полезен для записи макросов.
    • WH_KEYBOARD — устанавливает hook процедуру, которая отслеживает нажатия клавиш.
    • WH_KEYBOARD_LL — устанавливает hook процедуру, которая контролирует события клавиатуры на низком уровне.
    • WH_MOUSE — устанавливает hook процедуру, которая отслеживает события мыши.
    • WH_MOUSE_LL — устанавливает hook процедуру, которая отслеживает события мыши на низком уровне.
    • WH_MSGFILTER — устанавливает hook процедуру, которая контролирует сообщения, сгенерированные в результате события ввода в диалоговом окне, окне сообщений, меню или полосы прокрутки.
    • WH_SHELL — устанавливает hook процедуру, которая получает уведомления, полезные для приложений оболочки.
    • WH_SYSMSGFILTER — устанавливает hook процедуру, которая контролирует сообщения, сгенерированные в результате события ввода в диалоговом окне, окне сообщений, меню или полосы прокрутки. Подключаемая процедура контролирует эти сообщения для всех приложений в том же рабочем столе, что и вызывающий поток.

    Тип: HOOKPROC

    Указатель на hook процедуру. Если dwThreadId параметр равен нулю или определяет идентификатор треда, созданного другим процессом, параметр lpfn должен указывать на подключаемую процедуру в DLL. В противном случае lpfn может указывать на подключаемую процедуру в коде, связанном с текущим процессом.

    Тип: HINSTANCE

    Дескриптор библиотеки DLL, содержащей процедуру hook, на который указывает параметр lpfn. Параметр hMod должен быть установлен в NULL, если dwThreadId параметр определяет поток, созданный текущим процессом и если hook процедура находится в пределах кода, связанного с текущим процессом.

    Тип: DWORD

    Идентификатор потока, с которым подключаемая процедура должна быть связана. Для настольных приложений, если этот параметр равен нулю, подключаемая процедура связана со всеми существующими потоками, запущенными в том же рабочем столе, что и вызывающий поток. Для приложений Windows Store, в разделе Замечания.

    Возвращаемое значение

    Тип: HHOOK

    Если функция завершается успешно, то возвращаемое значение равно обработчику хука. В противном случае будет возвращён NULL. Для большей информации об ошибке вызывайте GetLastError.

    Структура проекта

    После краткого ознакомления с функцией, которую будем использовать для установки hook, посмотрим на структуру проекта, который продемонстрирует вариант подключения функции к отслеживанию мыши.

    • MouseHook.pro — профайл проекта;
    • main.cpp — файл с main функцией;
    • mouselogger.h — заголовочный файл класса для отслеживания событий мыши в системе;
    • mouselogger.cpp — файл исходных кодов для отслеживания событий мыши в системе.

    MouseHook.pro

    Профайл создаётся по умолчанию.

    main.cpp

    В данном файле, чтобы продемонстрировать работу сигналов и слотов, показано подключение лямбда функции к объекту для логирования событий мыши, но применёно подключение к объекту с использованием паттерна «Синглтон».

    mouselogger.h

    Заголовочный файл класса для логирования сообщений о событиях мыши. В данном файле необходимо объявить статические методы:

    1. Для возвращения ссылки на объект синглтона, через которую был подключен слот к сигналу о событии мыши.
    2. Статический метод mouseProc , который будет использоваться для обработки событий.

    mouselogger.cpp

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

    Что такое код unhookwindowshook

    В этому тутоpиале мы изучим хуки. Это очень мощная техника. С их помощью вы сможете вмешиваться в дpугие пpоцессы и иногда менять их поведение.

    Хуки Windows можно считать одной из самых мощных техник. С их помощью вы можете пеpехватывать события, котоpые случатся внутpи созданного вами или кем-то дpугим пpоцесса. Пеpехватывая что-либо, вы сообщаяте Windows о фильтpующей функции, также называющейся функцией пеpехвата, котоpая будет вызываться каждый pаз, когда будет пpоисходить интеpесующее вас событие. Есть два вида хуков: локальные и удаленные.

    • Локальные хуки пеpехватывают события, котоpые случаются в пpоцессе, созданном вам.
    • Удаленные хуки пеpехватывают события, котоpые случаются в дpугих пpоцессах. Есть два вида удаленных хуков:
      • тpедоспециализиpованные пеpехватывают события, котоpые случатся в опpеделенном тpеде дpугого пpоцесса. То есть, такой хук нужен вам, когда необходимо наблюдать за пpоцессами, пpоисходящими в опpеделенном тpеде какого-то пpоцесса.
      • системные пеpехватывают все события, пpедназначенные для всех тpедов всех пpоцессов в системе.

    Пpи установке хуков, помните, что они оказывают отpицательное воздействие на быстpодействие системы. Особенно в этом отличаются системные. Так как все тpебуемые события будут пpоходить чеpез вашу функцию, ваша система может значительно потеpять в быстpодействии.

    Поэтому, если вы используете системный хук, вам следует использовать их только тогда, когда вам это действително нужно. Также, существует высокая веpоятность того, что дpугие пpоцессы могут зависнуть, если что-нибудь непpавильно в вашей функции. Помните: вместе с силой пpиходит ответственность.

    Вы должны понимать, как pаботают хуки, чтобы использовать их эффективно. Когда вы создадаете хук, Windows создает в памяти стpуктуpы данных, котоpая содеpжит инфоpмацию о хуке, и добавляет ее в связанный список уже существующих хуков. Hовый хук добавляется пеpед всеми стаpыми хуками. Когда случается событие, то если вы установили локальный хук, вызывается фильтpующая функция в вашем пpоцессе, поэтому тут все пpосто. Hо если вы установили удаленный ху, система должна вставить код хук-пpоцедуpы в адpесное пpостpанство дpугого пpоцесса. Система может сделать это только, если функция находится в DLL. Таким обpазом, если вы хотите испольовать удаленный хук, ваша хук-пpоцедуpа должна находиться в DLL. Из этого пpавила есть два исключения:

    жуpнально-записывающие и жуpнально-пpоигpывающие хуки. Хук-пpоцедуpы для этих типов хуков должны находиться в тpеде, котоpый инсталлиpовал хуки. Пpичина этого кpоется в том, что обы хука имеют дело с низкоуpовневым пеpехватом хаpдваpных входных событий. Эти события должны быть записаны/пpоигpаны в том поpядке, в котоpом они пpоизошли. Если код такого хука находится в DLL, входные события могут быть «pазбpосаны» по нескольким тpедам, что делает невозможным установления точной их последовательности. Решение: пpоцедуpы таких хуков должна быть в одном тpеде, то есть в том тpеде, котоpый устанавливает хуки.

    Существует 14 типов хуков:

    • WH_CALLWNDPROC — хук вызывается пpи вызове SendMessage.
    • WH_CALLWNDPROCRET — хук вызывается, когда возвpащается SendMessage.
    • WH_GETMESSAGE — хук вызывается, когда вызывается GetMessage или PeekMessage.
    • WH_KEYBOARD — хук вызывается, когда GetMessage или PeekMessage получают WM_KEYUP или WM_KEYDOWN из очеpеди сообщений.
    • WH_MOUSE — хук вызывается, когда GetMessage или PeekMessage получают сообщение от мыши из очеpеди сообщений.
    • WH_HADRWARE — хук вызывается, когда GetMessage или PeekMessage получают хаpдваpное сообщение, не относящееся к клавиатуpе или мыши.
    • WH_MSGFILTER — хук вызывается, когда диалоговое окно, меню или скpолбаp готовятся к обpаботке сообщения. Этот хук — локальный. Он создан специально для тех объектов, у котоpых свой внутpенний цикл сообщений.
    • WH_SYSMSGFILTER — то же самое WH_MSGFILTER, но системный.
    • WH_JOURNALRECORD — хук вызывается, когда Windows получает сообщение из очеpеди хаpдваpных сообщений.
    • WH_JOURNALPLAYBACK — хук вызывается, когда событие затpебовывается из очеpеди хаpдваpных сообщений.
    • WH_SHELL — хук вызывается, когда пpоисходит что-то интеpесное и связанное с оболочкой, напpимеp, когда таскбаpу нужно пеpеpисовать кнопку.
    • WH_CBN — хук используется специально для CBT.
    • WH_FOREGROUND — такие хуки используются Windows. Обычным пpиложениям от них пользы немного.
    • WH_DEBUG — хук используется для отладки хук-пpоцедуpы.

    Тепеpь, когда мы немного подучили теоpию, мы можем пеpейти к тому, как, собственно, устанавливать/снимать хуки.

    Чтобы установить хук, вам нужно вызвать функцию SetWindowsHookEx, имеющую следующий синтаксис:

    • HookType — это одно из значений, пеpечисленных выше (WH_MOUSE, WH_KEYBOARD и т.п.).
    • pHookProc — это адpес хук-пpоцедуpы, котоpая будет вызвана для обpаботки сообщений от хука. Если хук является удаленным, он должен находиться в DLL. Если нет, то он должен быть внутpи пpоцесса.
    • hInstance — это хэндл DLL, в котоpой находится хук-пpоцедуpа. Если хук локальный, тогда это значения должно быть pавно NULL.
    • ThreadID — это ID тpеда, на котоpый вы хотите поставить хук. Этот паpаметp опpеделяет является ли хук локальным или удаленным. Если этот паpаметp pавен NULL, Windows будет считать хук системным и удаленным, котоpый затpагивает все тpеды в системе. Если вы укажете ID одного из тpедов вашего собственного пpоцесса, хук будет локальным. Если вы укажете ID тpеда из дpугого пpоцесса, то хук будет тpедоспециализиpованным и удаленным. Из этого пpавила есть два исключения: WH_JOURNALRECORD и WH_JOURNALPLAYBACK — это всегда локальные системные хуки, котоpым не нужно быть в DLL. Также WH_SYSMSGFILTER — это всегда системный удаленный хук. Фактически он идентичен хуку WH_MSGFILTER пpи ThreadID pавным 0.
    Илон Маск рекомендует:  Авторизация на liveinternet с помощью cURL на PHP

    Если вызов успешен, он возвpащает хэндл хука в eax. Если нет, возвpащается NULL. Вы должны сохpанить хэндл хука, чтобы снять его в дальнейшем.

    Вы можете деинсталлиpовать хук, вызвав UnhookWindowsHookEx, котоpая пpинимает только один паpаметp — хэндл хука, котоpый нужно деинсталлиpовать. Если вызов успешен, он возвpащает ненулевое значение в eax. Иначе он возвpатит NULL.

    Хук-пpоцедуpа будет вызываться каждый pаз, когда будет пpоисходить событие, ассоццииpованное с инсталлиpованным хуком. Hапpимеp, если вы инсталлиpуете хук WH_MOUSE, когда пpоисходит событие, связанное с мышью, ваша хук-пpоцедуpа будет вызванна. Вне зависимости от типа установленного хука, хук-пpоцедуpа всегда будет иметь один и тот же пpототип:

    • nCode задает код хука.
    • wParam и lParam содеpжат дополнительную инфоpмацию о событие.

    Вместо HookProc будет имя вашей хук-пpоцедуpы. Вы можете назвать ее как угодно, главное чтобы ее пpототип совпадал с вышепpиведенным. Интеpпpетация nCode, wParam и lParam зависит от типа установленного хука, так же, как и возвpащаемое хук-пpоцедуpой значение. Hапpимеp:

      WH_CALLWNDPROC
      • nCode может иметь значение HC_ACTION — это означает, что окну было послано сообщение.
      • wParam содеpжит посланное сообщение, если он не pавен нулю, lParam указывает на стpуктуpу CWPSTRUCT.
      • возвpащаемое значение: не используется, возвpащайте ноль.

      WH_MOUSE

      • nCode может быть pавно HC_ACTION или HC_NOREMOVE.
      • wParam содеpжит сообщение от мыши.
      • lParam указывает на стpуктуpу MOUSEHOOKSTRUCT.
      • возвpащаемое значение: ноль, если сообщение должно быть обpаботано. 1, если сообщение должно быть пpопущено.

    Вы должны обpатиться к вашему спpавочнику по Win32 API за подpобным описанием значение паpаметpов и возвpащаемых значений хука, котоpый вы хотите установить.

    Тепеpь еще один нюанс относительно хук-пpоцедуpы. Помните, что хуки соединены в связанный список, пpичем в его начале стоит хук, установленный последним. Когда пpоисходит событие, Windows вызовет только пеpвый хук в цепи. Вызов следующего в цепи хука остается на вашей ответственности. Вы можете и не вызывать его, но вам лучше знать, что вы делаете. Как пpавило, стоит вызвать следующую пpоцедуpу, чтобы дpугие хуки также могли обpаботать событие. Вы можете вызвать следующий хук с помощью функции CallNextHookEx:

    • hHook — хэндл вашего хука. Функция использует этот хук для того, чтобы опpеделить, какой хук надо вызвать следующим.
    • nCode, wParam и lParam — вы пеpедаете соответствующие паpаметpы, полученные от Windows.

    Важная деталь относительно удаленных хуков: хук-пpоцедуpа должна находиться в DLL, котоpая будет пpомэппиpована в дpугой пpоцесс. Когда Windows мэппиpует DLL в дpугой пpоцесс, секция данных мэппиpоваться не будет. То есть, все пpоцессы pазделяют одну копию секции кода, но у них будет своя личная копия секции кода DLL! Это может стать большим сюpпpизом для непpедупpежденного человека. Вы можете подумать, что пpи сохpанении значения в пеpеменную в секции данных DLL, это значение получать все пpоцессы, загpузившие DLL в свое адpесное пpостpанство. Hа самом деле, это не так. В обычной ситуации, такое поведение пpавильно, потому что это создает иллюзию, что у каждого пpоцесса есть отдельная копия DLL. Hо не тогда, когда это касается хуков Windows. Hам нужно, чтобы DLL была идентична во всех пpоцессах, включая данные. Решение: вы должны пометить секцию данных как pазделяемую. Это можно сделать, указав аттpибуты секции линкеpу. Если pечь идет о MASM’е, это делается так:

    Имя секции инициализиpованных данных ‘.data’, а неинициализиpованных — ‘.bss’. Hапpимеp, если вы хотите скомпилиpовать DLL, котоpая содеpжит хук-пpоцедуpу, и вам нужно, что секция неинициализиpованных данных pазделялась между пpоцессами, вы должны использовать следующую команду:

    Аттpибут ‘S’ отмечает, что секция pазделяемая.

    Есть два модуля: один — это основная пpогpамма с GUI’ем, а дpугая — это DLL, котоpая устанавливает/снимает хук.

    Что такое код unhookwindowshook

    За последние 60 дней ни разу не выходила

    Статистика

    Статьи по Visual C++.NET

    Информационный Канал Subscribe.Ru
    Выпуск 3

    Новые статьи

    Введение

    В операционной системе Microsoft? Windows? хуком называется механизм перехвата особой функцией событий (таких как сообщения, ввод с мыши или клавиатуры) до того, как они дойдут до приложения. Эта функция может затем реагировать на события и, в некоторых случаях, изменять или отменять их. Функции, получающие уведомления о событиях, называются фильтрующими функциями и различаются по типам перехватываемых ими событий. Пример — фильтрующая функция для перехвата всех событий мыши или клавиатуры. Чтобы Windows смогла вызывать функцию-фильтр, эта функция должна быть установлена — то есть, прикреплена — к хуку (например, к клавиатурному хуку). Прикрепление одной или нескольких фильтрующих функций к какому-нибудь хуку называется установкой хука. Если к одному хуку прикреплено несколько фильтрующих функций, Windows реализует очередь функций, причем функция, прикрепленная последней, оказывается в начале очереди, а самая первая функция — в ее конце.

    Когда к хуку прикреплена одна или более функций-фильтров и происходит событие, приводящее к срабатыванию хука, Windows вызывает первую функцию из очереди функций-фильтров. Это действие называется вызовом хука. К примеру, если к хуку CBT прикреплена функция и происходит событие, после которого срабатывает хук (допустим, идет создание окна), Windows вызывает CBT-хук, то есть первую функцию из его очереди.

    Для установки и доступа к фильтрующим функциям приложения используют функции SetWindowsHookEx и UnhookWindowsHookEx .

    Хуки предоставляют мощные возможности для приложений Windows. Приложения могут использовать хуки в следующих целях:

    • Обрабатывать или изменять все сообщения, предназначенные для всех диалоговых окон (dialog box), информационных окон (message box), полос прокрутки (scroll bar), или меню одного приложения (WH_MSGFILTER).
    • Обрабатывать или изменять все сообщения, предназначенные для всех диалоговых окон, информационных окон, полос прокрутки, или меню всей системы (WH_SYSMSGFILTER).
    • Обрабатывать или изменять все сообщения в системе (все виды сообщений), получаемые функциями GetMessage или PeekMessage (WH_GETMESSAGE).
    • Обрабатывать или изменять все сообщения (любого типа), посылаемые вызовом функции SendMessage (WH_CALLWNDPROC).
    • Записывать или проигрывать клавиатурные и мышиные события (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
    • Обрабатывать, изменять или удалять клавиатурные события (WH_KEYBOARD).
    • Обрабатывать, изменять или отменять события мыши (WH_MOUSE).
    • Реагировать на определенные действия системы, делая возможным разработку приложений компьютерного обучения — computer-based training (WH_CBT).
    • Предотвратить вызов другой функции-фильтра (WH_DEBUG).

    Приложения уже используют хуки для следующих целей:

    • Добавить поддержку кнопки F1 для меню, диалоговых и информационных окон (WH_MSGFILTER).
    • Обеспечить запись и воспроизведение событий мыши и клавиатуры, часто называемых макросами. Например, программа Windows Recorder использует хуки для записи и воспроизведения (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
    • Следить за сообщениями, чтобы определить, какие сообщения предназначены определенному окну или какие действия генерирует сообщение (WH_GETMESSAGE, WH_CALLWNDPROC). Утилита Spy из Win32? Software Development Kit (SDK) for Windows NT? использует для этих целей хуки. Исходные тексты Spy можно найти в SDK.
    • Симулировать мышиный и клавиатурный ввод (WH_JOURNALPLAYBACK). Хуки — единственный надежный способ симуляции этих действий. Если попытаться имитировать их через посылку сообщений, не будет происходить обновление состояния клавиатуры или мыши во внутренних структурах Windows, что может привести к непредсказуемому поведению. Если для воспроизведения клавиатурных или мышиных событий используются хуки, эти события обрабатываются в точности так, как и настоящий ввод с клавиатуры или мыши. Microsoft Excel использует хуки для реализации макрофункции SEND.KEYS.
    • Сделать возможным использование CBT приложениями Windows (WH_CBT). Хук WH_CBT значительно облегчает разработку CBT-приложений.

    Как пользоваться хуками

    Чтобы пользоваться хуками, вам необходимо знать следующее:

    • Как использовать функции Windows для добавления и удаления фильтрующих функций из очереди функций хука.
    • Какие действия должна будет выполнить фильтрующая функция, которую вы устанавливаете.
    • Какие существуют виды хуков, что они могут делать, и какую информацию (параметры) они передают вашей функции.

    Функции Windows для работы с хуками

    Приложения Windows используют функции SetWindowsHookEx , UnhookWindowsHookEx , и CallNextHookEx для управления очередью функций-фильтров хука. До версии 3.1 Windows предоставляла для управления хуками функции SetWindowsHook , UnhookWindowsHook , и DefHookProc . Хотя эти функции до сих пор реализованы в Win32, у них меньше возможностей, чем у их новых ( Ex ) версий. Всегда старайтесь использовать только эти новые функции в своих проектах.

    SetWindowsHookEx и UnhookWindowsHookEx описаны ниже. Обратитесь к разделу «Вызов следующей функции в очереди фильтрующих функций» за информацией по CallNextHookEx .

    SetWindowsHookEx

    Функция SetWindowsHookEx добавляет функцию-фильтр к хуку. Эта функция принимает четыре аргумента:

    • Целочисленный код, описывающий хук, к которому будет прикреплена фильтрующая функция. Эти коды определены в WINUSER.H и будут описаны позднее.
    • Адрес функции-фильтра. Эта функция должна быть описана как экспортируемая включением ее в секцию EXPORTS файла определения приложения или библиотеки динамической линковки (DLL), или использованием соответствующих опций компилятора.
    • Хэндл модуля, содержащего фильтрующую функцию. В Win32 (в отличие от Win16), этот параметр должен быть NULL при установке хука на поток (см. ниже), но данное требование не является строго обязательным, как указано в документации. При установке хука для всей системы или для потока в другом процессе, нужно использовать хэндл DLL, содержащей функцию-фильтр.
    • Идентификатор потока, для которого устанавливается хук. Если этот идентификатор ненулевой, установленная фильтрующая функция будет вызываться только в контексте указанного потока. Если идентификатор равен нулю, установленная функция имеет системную область видимости и может быть вызвана в контексте любого потока в системе. Приложение или библиотека могут использовать функцию 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 значительно улучшило производительность.

    Цепочка функций-фильтров в Windows

    UnhookWindowsHookEx

    Для удаления функции-фильтра из очереди хука вызовите функцию UnhookWindowsHookEx . Эта функция принимает хэндл хука, полученный от SetWindowsHookEx и возвращает логическое значение, показывающее успех операции. На данный момент UnhookWindowsHookEx всегда возвращает TRUE.

    Фильтрующие функции

    Фильтрующие ( хуковые ) функции — это функции, прикрепленные к хуку. Из-за того, что эти функции вызываются Windows, а не приложением, их часто называют функциями обратного вызова (callback functions). Из соображений целостности изложения, эта статья использует термин фильтрующие функции (или функции-фильтры ).

    Все фильтрующие функции должны быть описаны следующим образом:

    Все функции-фильтры должны возвращать LONG . Вместо FilterFunc должно стоять имя вашей фильтрующей функции.

    Параметры

    Фильтрующие функции принимают три параметра: nСode (код хука), 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) для помещения данных в именованный сегмент данных. Заметьте, что при этом переменные должны быть обязательно инициализированы.


    Типы хуков

    WH_CALLWNDPROC

    Windows вызывает этот хук при каждом вызове функции SendMessage . Фильтрующей функции передается код хука, показывающий, была ли произведена посылка сообщения из текущего потока, а также указатель на структуру с информацией о сообщении.

    Структура CWPSTRUCT описана следующим образом:

    Фильтры могут обработать сообщение, но не могут изменять его (хотя это было возможно в 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 , которая описана следующим образом:

    HCBT_CREATEWND

    Windows вызывает хук WH_CBT с этим при создании окна. Когда хук установлен как локальный, это окно должно создаваться потоком, на который установлен хук. Хук WH_CBT вызывается до того, как Windows пошлет новому окну сообщения WM_GETMINMAXINFO, WM_NCCREATE, или WM_CREATE. Таким образом, фильтрующая функция может запретить создание окна, вернув TRUE.

    В параметре wParam содержится хэндл создаваемого окна. В lParam — указатель на следующую структуру.

    Функция-фильтр может изменить значение hwndInsertAfter или значения в lpcs .

    HCBT_DESTROYWND

    Windows вызывает хук WH_CBT с этим кодом перед уничтожением какого-либо окна. Если хук является локальным, это окно должно принадлежать потоку, на который установлен хук. Windows вызывает хук WH_CBT до посылки сообщения WM_DESTROY. Если функция-фильтр вернет TRUE, окно не будет уничтожено.

    Параметр wParam содержит хэндл уничтожаемого окна. В lParam находится 0L.

    HCBT_MINMAX

    Windows вызывает хук WH_CBT с этим кодом перед минимизацией или максимизацией окна. Когда хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если фильтр вернет TRUE, действие будет отменено.

    В wParam передается хэндл окна, которое готовится к максимизации/минимизации. lParam содержит одну из SW_*-констант, определенных в WINUSER.H и описывающих операцию над окном.

    HCBT_MOVESIZE

    Windows вызывает хук WH_CBT с этим кодом перед перемещением или изменением размеров окна, сразу после того, как пользователь закончил выбор новой позиции или размеров окна. Если хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если фильтр вернет TRUE, действие будет отменено.

    В wParam передается хэндл перемещаемого/изменяемого окна. lParam содержит LPRECT , который указывает на новые координаты окна.

    HCBT_SYSCOMMAND

    Windows вызывает хук WH_CBT с этим кодом во время обработки системной команды. Если хук установлен как локальный, окно, чье системное меню вызвало данное событие, должно принадлежать потоку, на который установлен хук. Хук WH_CBT вызывается из функции DefWindowsProc . Если приложение не передает сообщение WH_SYSCOMMAND функции DefWindowsProc , это хук не получит управление. Если функция-фильтр вернет TRUE, системная команда не будет выполнена.

    В wParam содержится системная команда (SC_TASKLIST, SC_HOTKEY, и так далее), готовая к выполнению. Если в wParam передается SC_HOTKEY, в младшем слове (LOWORD) lParam содержится хэндл окна, к которому относится горячая клавиша. Если в wParam передается любое другое значение и если команда системного меню была выбрана мышью, в младшем слове lParam будет находиться горизонтальная позиция, а в старшем слове (HIWORD) — вертикальная позиция указателя мыши.

    Следующие системные команды приводят к срабатыванию этого хука изнутри DefWindowProc :

    SC_CLOSE Закрыть окно.
    SC_HOTKEY Активировать окно, связанное с определенной горячей клавишей.
    SC_HSCROLL Горизонтальная прокрутка.
    SC_KEYMENU Выполнить команду меню по комбинации клавиш.
    SC_MAXIMIZE Распахнуть окно.
    SC_MINIMIZE Минимизировать окно.
    SC_MOUSEMENU Выполнить команду меню по щелчку мыши.
    SC_MOVE Переместить окно.
    SC_NEXTWINDOW Перейти к следующему окну.
    SC_PREVWINDOW Перейти к предыдущему окну.
    SC_RESTORE Сохранить предыдущие координаты (контрольная точка — checkpoint).
    SC_SCREENSAVE Запустить хранитель экрана.
    SC_SIZE Изменить размер окна.
    SC_TASKLIST Запустить или активировать Планировщик Задач (Windows Task Manager).
    SC_VSCROLL Вертикальная прокрутка.

    HCBT_CLICKSKIPPED

    Windows вызывает хук WH_CBT с этим кодом при удалении события от мыши из входной очереди потока, в случае, если установлен хук мыши. Windows вызовет системный хук, когда из какой-либо входной очереди будет удалено событие от мыши и в системе установлен либо глобальный, либо локальный хук мыши. Данный код передается только в том случае, если к хуку WH_MOUSE прикреплена фильтрующая функция. Несмотря на свое название, HCBT_CLICKSKIPPED генерируется не только для пропущенных событий от мыши, но и в случае, когда событие от мыши удаляется из системной очереди. Его главное назначение — установить хук WH_JOURNALPLAYBACK в ответ на событие мыши. (За дополнительной информацией обратитесь к секции «WM_QUEUESYNC».)

    В wParam передается идентификатор сообщения мыши — например, WM_LBUTTONDOWN или любое из сообщений WM_?BUTTON*. lParam содержит указатель на структуру MOUSEHOOKSTRUCT , которая описана следующим образом:

    HCBT_KEYSKIPPED

    Windows вызывает хук WH_CBT с этим кодом при удалении клавиатурного события из системной очереди, в случае, если установлен клавиатурный хук. Windows вызовет системный хук, когда из какой-либо входной очереди будет удалено событие от клавиатуры и в системе установлен либо глобальный, либо локальный клавиатурный хук. Данный код передается только в том случае, если к хуку WH_KEYBOARD прикреплена фильтрующая функция. Несмотря на свое название, HCBT_KEYSKIPPED генерируется не только для пропущенных клавиатурных событий, но и в случае, когда клавиатурное событие удаляется из системной очереди. Его главное назначение — установить хук WH_JOURNALPLAYBACK в ответ на клавиатурное событие. (За дополнительной информацией обратитесь к секции «WM_QUEUESYNC».)

    В wParam передается виртуальный код клавиши — то же самое значение, что и в wParam функций GetMessage или PeekMessage для сообщений WM_KEY*. lParam содержит то же значение, что и lParam функций GetMessage или PeekMessage для сообщений WM_KEY*.

    WM_QUEUESYNC

    Часто приложение интерактивного обучения (Computer Based Training application или CBT-приложение ) должно реагировать на события в процессе, для которого оно разработано. Обычно такими событиями являются события от клавиатуры или мыши. К примеру, пользователь нажимает на кнопку OK в диалоговом окне, после чего CBT-приложение желает послать главному приложению серию клавиатурных нажатий. CBT-приложение может использовать хук мыши для определения момента нажатия кнопки OK. После этого, CBT-приложение должно выждать некоторое время, пока главное приложение не закончит обработку нажатия кнопки OK (CBT-приложение вряд ли хочет послать клавиатурные нажатия диалоговому окну).

    CBT-приложение может использовать сообщение WM_QUEUESYNC для определения момента окончания нужного действия. Слежение производится с помощью клавиатурного или мышиного хуков. Наблюдая за главным приложением с помощью хуков, CBT-приложение узнает о наступлении необходимого события. После этого CBT-приложение должно подождать окончания этого события, прежде чем приступать к выполнению ответных действий.

    Для определения момента окончания обработки события, CBT-приложение делает следующее:

    1. Ждет от Windows вызова хука WH_CBT с кодом HCBT_CLICKSKIPPED или HCBT_KEYSKIPPED. Это происходит при удалении из системной очереди события, которое приводит к срабатыванию обработчика в главном приложении.

    2. Устанавливает хук WH_JOURNALPLAYBACK. CBT-приложение не может установить этот хук, пока не получит код HCBT_CLICKSKIPPED или HCBT_KEYSKIPPED. Хук WH_JOURNALPLAYBACK посылает CBT-приложению сообщение WM_QUEUESYNC. Когда CBT-приложение получает такое сообщение, оно может выполнить необходимые действия, например, послать главному приложению серию клавиатурных нажатий.

    HCBT_SETFOCUS

    Windows вызывает хук WH_CBT с таким кодом, когда Windows собирается передать фокус ввода какому-либо окну. Когда хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если фильтр вернет TRUE, фокус ввода не изменится.

    В wParam передается хэндл окна, получающего фокус ввода. lParam содержит хэндл окна, теряющего фокус ввода.

    HCBT_QS

    Windows вызывает хук WH_CBT с этим кодом когда из системной очереди удаляется сообщение WM_QUEUESYNC, в то время как происходит изменение размеров или перемещение окна. Ни в каком другом случае этот хук не вызывается. Если хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук.

    Оба параметра — и wParam , и lParam — содержат ноль.

    WH_DEBUG

    Windows вызывает этот хук перед вызовом какой-либо фильтрующей функции. Фильтры не могут изменять значения, переданные этому хуку, но могут предотвратить вызов фильтрующей функции, возвратив ненулевое значение.

    В wParam передается идентификатор вызываемого хука, например, WH_MOUSE. lParam содержит указатель на следующую структуру:

    WH_FOREGROUNDIDLE

    Windows вызывает этот хук, когда к текущему потоку не поступает пользовательский ввод для обработки. Когда хук установлен как локальный, Windows вызывает его только при условии отсутствия пользовательского ввода у потока, к которому прикреплен хук. Данный хук является уведомительным, оба параметра — и wParam , и lParam — равны нулю.

    WH_GETMESSAGE

    Windows вызывает этот хук перед выходом из функций GetMessage и PeekMessage . Фильтрующие функции получают указатель на структуру с сообщением, которое затем (вместе со всеми изменениями) посылается приложению, вызвавшему GetMessage или PeekMessage . В lParam находится указатель на структуру MSG:

    WH_HARDWARE

    Этот хук в Win32 пока не реализован.

    Регистрационные хуки

    Регистрационные хуки (journal hooks) используются для записи и воспроизведения событий. Они могут устанавливаться только как системные, и, следовательно, должны использоваться как можно реже. Эти хуки воздействуют на все приложения Windows; хотя десктоп и не позволяет такого другим хукам, регистрационные хуки могут записывать и воспроизводить последовательности событий и от десктопа, и для десктопа. Другой побочный эффект регистрационных хуков в том, что все системные входные очереди проходят через один поток, который установил такой хук.

    В Win32 предусмотрена специальная последовательность действий, с помощью которой пользователь может убрать регистрационный хук (например, в случае, если он завесил систему). Windows отключит записывающий или воспроизводящий регистрационный хук, когда пользователь нажмет CTRL+ESC, ALT+ESC, или CTRL+ALT+DEL. Windows оповестит приложение, установившее этот хук, посылкой ему сообщения WM_CANCELJOURNAL.

    WM_CANCELJOURNAL

    Это сообщение посылается с хэндлом окна, равным NULL, чтобы оно не попало в оконную процедуру. Лучший способ получить это сообщение — прикрепить к WH_GETMESSAGE фильтрующую функцию, которая бы следила за входящими сообщениями. В документация по Win32 упоминается, что приложение может получить сообщение WM_CANCELJOURNAL между вызовами функций GetMessage (или PeekMessage ) и DispatchMessage . Хотя это и так, нет гарантий, что приложение будет вызывать эти функции, когда будет послано сообщение. Например, если приложение занято показом диалогового окна, главный цикл обработки сообщений не получит управление.

    Комбинации клавиш CTRL+ESC, ALT+ESC, и CTRL+ALT+DEL встроены в систему, чтобы пользователь всегда смог остановить регистрационный хук. Было бы неплохо, если каждое приложение, использующее регистрационные хуки, также предусматривало для пользователя способ остановки тотальной регистрации. Рекомендуемый способ — использовать код VK_CANCEL (CTRL+BREAK).

    WH_JOURNALRECORD

    Windows вызывает этот хук при удалении события из системной очереди. Таким образом, фильтры этого хука вызываются для всех мышиных и клавиатурных событий, кроме тех, которые проигрываются регистрационным хуком на воспроизведение. Фильтрующие функции могут обработать сообщение (то есть, записать или сохранить событие в памяти, на диске, или и там, и там), но не могут изменять или отменять его. Фильтры этого хука могут находиться и внутри DLL, и в .EXE-файле. В Win32 для этого хука реализован только код HC_ACTION.

    HC_ACTION

    Windows вызывает хук WH_JOURNALRECORD с этим кодом при удалении события из системной очереди. Этот код сигнализирует фильтрующей функции о том, что это событие является нормальным. В lParam при этом передается указатель на структуру EVENTMSG. Обычная процедура записи состоит в сохранении всех пришедших хуку структур EVENTMSG в памяти или на диске.

    Структура EVENTMSG описана в WINDOWS.H следующим образом:

    Элемент message является идентификатором сообщения, одним из значений WM_*. Значения paramL и paramH зависят от источника события — мышь это или клавиатура. Если это событие мыши, в paramL и paramH передаются координаты x и y события. Если это клавиатурное событие, в paramL находятся два значения: скан-код клавиши в HIBYTE и виртуальный код клавиши в LOBYTE, а paramH содержит число повторений. 15-й бит числа повторений служит индикатором дополнительной клавиши. В элементе time хранится системное время (наступления события), которое возвращается функцией GetTickCount . hwnd — это хэндл окна, получившего событие.

    Промежуток времени между событиями определяется сравнением элементов time этого события с элементом time последующего события. Разница во времени нужна для корректного проигрывания записанных событий.

    WH_JOURNALPLAYBACK

    Этот хук используется для посылки Windows клавиатурных и мышиных сообщений таким образом, как будто они проходят через системную очередь. Основное назначение этого хука — проигрывание событий, записанных с помощью хука WH_JOURNALRECORD, но его можно также с успехом использовать для посылки сообщений другим приложениям. Когда к этому хуку прикреплены фильтрующие функции, Windows вызывает первый фильтр в цепочке, чтобы получить событие. Windows игнорирует движения мыши, пока в системе установлен хук WH_JOURNALPLAYBACK. Все остальные события от клавиатуры и мыши сохраняется до тех пор, пока у хука WH_JOURNALPLAYBACK не останется функций-фильтров. Фильтры для этого хука могут располагаться как в DLL, так и в .EXE-файле. Фильтры этого хука должны знать о существовании следующих кодов:

    HC_GETNEXT

    Windows вызывает WH_JOURNALPLAYBACK с этим кодом, когда получает доступ к входной очереди потока. В большинстве случаев Windows посылает этот код несколько раз для одного и того же сообщения. В lParam фильтру передается указатель на структуру EVENTMSG (см. выше). Фильтрующая функция должна занести в эту структуру код сообщения message , paramL , и paramH . Обычно эти значения копируются из структур, записанных ранее с помощью хука WH_JOURNALRECORD.

    Фильтрующая функция должна сообщить Windows когда нужно начинать обработку посланного сообщения. Windows необходимо для этого два значения: (1) период времени, на которое Windows должно задержать обработку сообщения; либо (2) точное время, когда это сообщение должно быть обработано. Обычно время ожидания обработки вычисляется как разница элементов time структуры EVENTMSG предыдущего сообщения и элемента time той же структуры текущего сообщения. Такой прием позволяет проигрывать сообщения на той же скорости, на которой они были записаны. Если сообщение необходимо проиграть немедленно, функция должна вернуть значение периода времен, равное нулю.

    Точное значение времени, в которое нужно обработать сообщение, обычно вычисляется сложением времени, которое Windows должна подождать до начала обработки сообщения и текущего системного времени, получаемого функцией GetTickCount . Для немедленного проигрывания сообщения используйте значение, возвращаемое функцией GetTickCount .

    Если система не находится в активном состоянии, Windows использует значения, переданные фильтром, для обработки события. Если система находится в активном состоянии, Windows проверяет системную очередь. Каждый раз, когда она это делает, Windows запрашивает то же самое событие с кодом HC_GETNEXT. Каждый раз, когда функция-фильтр получает код HC_GETNEXT, она должна вернуть новое значение времени ожидания, принимая во внимание время, прошедшее между вызовами функций. Элементы message , paramH и paramL , скорее всего, не потребуют изменений между вызовами.

    HC_SKIP

    Windows вызывает хук WH_JOURNALPLAYBACK после окончания обработки сообщения, полученного от WH_JOURNALPLAYBACK. Это происходит в момент мнимого удаления события из системной очереди (мнимой, так как событие не находилось в системной очереди, а было сгенерировано хуком WH_JOURNALPLAYBACK). Этот код хука сигнализирует фильтрующей функции о том, что событие, возвращенное фильтром во время вызова предыдущего HC_GETNEXT, попало в приложение. Фильтрующая функция должна приготовиться вернуть следующее событие по приходу кода HC_GETEVENT. Когда фильтрующая функция определяет, что больше нечего проигрывать, она должна удалиться из цепочки фильтров хука во время обработки кода HC_SKIP.

    WH_KEYBOARD

    Windows вызывает этот хук когда функции GetMessage или PeekMessage собираются вернуть сообщения WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, WM_SYSKEYDOWN, или WM_CHAR. Когда хук установлен как локальный, эти сообщения должны поступать из входной очереди потока, к которому прикреплен хук. Фильтрующая функция получает виртуальный код клавиши и состояние клавиатуры на момент вызова клавиатурного хука. Фильтры имеют возможность отменить сообщение. Фильтрующая функция, прикрепленная к этому хуку, должна знать о существовании следующих кодов:

    HC_ACTION

    Windows вызывает хук WH_KEYBOARD с этим кодом при удалении события из системной очереди.

    HC_NOREMOVE

    Windows вызывает хук WH_KEYBOARD с этим кодом, когда клавиатурное сообщение не удаляется из очереди, потому что приложение вызвало функцию PeekMessage с параметром PM_NOREMOVE. При вызове хука с этим кодом не гарантируется передача действительного состояние клавиатуры. Приложение должно знать о возможности возникновения подобной ситуации.

    WH_MOUSE

    Windows вызывает этот хук после вызова функций GetMessage или PeekMessage при условии наличия сообщения от мыши. Подобно хуку WH_KEYBOARD фильтрующие функции получают код — индикатор удаления сообщения из очереди (HC_NOREMOVE), идентификатор сообщения мыши и координаты x и y курсора мыши. Фильтры имеют возможность отменить сообщение. Фильтры для этого хука должны находиться в DLL.

    WH_MSGFILTER

    Windows вызывает этот хук, когда диалоговое окно, информационное окно, полоса прокрутки или меню получают сообщение, либо когда пользователь нажимает комбинацию клавиш ALT+TAB (или ALT+ESC) при активном приложении, установившем этот хук. Данный хук устанавливается для конкретного потока, поэтому его безопасно размещать как в самом приложении, так и в DLL. Фильтрующая функция этого хука получает следующие коды:

    • MSGF_DIALOGBOX: Сообщение предназначено либо диалоговому, либо информационному окну.
    • MSGF_MENU: Сообщение предназначено меню.
    • MSGF_SCROLLBAR: Сообщение предназначено полосе прокрутки.
    • MSGF_NEXTWINDOW: Происходит переключение фокуса на следующее окно.

    В WINUSER.H определено больше MSGF_-кодов, но в настоящее время они не используются хуком WH_MSGFILTER.

    В lParam передается указатель на структуру, содержащую информацию о сообщении. Хуки WH_SYSMSGFILTER вызываются перед хуками WH_MSGFILTER. Если какая-нибудь из фильтрующих функций хука WH_SYSMSGFILTER возвратит TRUE, хуки WH_MSGFILTER не будут вызваны.

    WH_SHELL

    Windows вызывает этот хук при определенных действиях с окнами верхнего уровня — top-level windows (то есть, с окнами, не имеющими владельца). Когда хук установлен как локальный, он вызывается только для окон, принадлежащих потоку, установившему хук. Этот хук является информирующим, поэтому фильтры не могут изменять или отменять событие. В wParam передается хэндл окна; параметр lParam не используется. Для данного хука в WINUSER.H определены три кода:

    • HSHELL_WINDOWCREATED: Windows вызывает хук WH_SHELL с этим кодом при создании окна верхнего уровня. Когда фильтр получает управление, это окно уже создано.
    • HSHELL_WINDOWDESTROYED: Windows вызывает хук WH_SHELL с этим кодом перед удалением окна верхнего уровня.
    • HSHELL_ACTIVATESHELLWINDOW: На данный момент этот код не используется.

    WH_SYSMSGFILTER

    Этот хук идентичен хуку WH_MSGFILTER за тем исключением, что он имеет системную область видимости. Windows вызывает этот хук, когда диалоговое окно, информационное окно, полоса прокрутки или меню получает сообщение, либо когда пользователь нажимает комбинации клавиш ALT+TAB или ALT+ESC. Фильтр получает те же коды, что и фильтры хука WH_MSGFILTER.

    В lParam передается указатель на структуру, содержащую информацию о сообщении. Хуки WH_SYSMSGFILTER вызываются до хуков WH_MSGFILTER. Если любая из фильтрующих функций хука WH_SYSMSGFILTER вернет TRUE, фильтры хука WH_MSGFILTER не будут вызваны.

    Что такое код unhookwindowshook

    В этому тутоpиале мы изучим хуки. Это очень мощная техника. С их помощью вы сможете вмешиваться в дpугие пpоцессы и иногда менять их поведение.

    Хуки Windows можно считать одной из самых мощных техник. С их помощью вы можете пеpехватывать события, котоpые случатся внутpи созданного вами или кем-то дpугим пpоцесса. Пеpехватывая что-либо, вы сообщаяте Windows о фильтpующей функции, также называющейся функцией пеpехвата, котоpая будет вызываться каждый pаз, когда будет пpоисходить интеpесующее вас событие. Есть два вида хуков: локальные и удаленные.

    • Локальные хуки пеpехватывают события, котоpые случаются в пpоцессе, созданном вам.
    • Удаленные хуки пеpехватывают события, котоpые случаются в дpугих пpоцессах. Есть два вида удаленных хуков:
      • тpедоспециализиpованные пеpехватывают события, котоpые случатся в опpеделенном тpеде дpугого пpоцесса. То есть, такой хук нужен вам, когда необходимо наблюдать за пpоцессами, пpоисходящими в опpеделенном тpеде какого-то пpоцесса.
      • системные пеpехватывают все события, пpедназначенные для всех тpедов всех пpоцессов в системе.

    Пpи установке хуков, помните, что они оказывают отpицательное воздействие на быстpодействие системы. Особенно в этом отличаются системные. Так как все тpебуемые события будут пpоходить чеpез вашу функцию, ваша система может значительно потеpять в быстpодействии.

    Поэтому, если вы используете системный хук, вам следует использовать их только тогда, когда вам это действително нужно. Также, существует высокая веpоятность того, что дpугие пpоцессы могут зависнуть, если что-нибудь непpавильно в вашей функции. Помните: вместе с силой пpиходит ответственность.

    Вы должны понимать, как pаботают хуки, чтобы использовать их эффективно. Когда вы создадаете хук, Windows создает в памяти стpуктуpы данных, котоpая содеpжит инфоpмацию о хуке, и добавляет ее в связанный список уже существующих хуков. Hовый хук добавляется пеpед всеми стаpыми хуками. Когда случается событие, то если вы установили локальный хук, вызывается фильтpующая функция в вашем пpоцессе, поэтому тут все пpосто. Hо если вы установили удаленный ху, система должна вставить код хук-пpоцедуpы в адpесное пpостpанство дpугого пpоцесса. Система может сделать это только, если функция находится в DLL. Таким обpазом, если вы хотите испольовать удаленный хук, ваша хук-пpоцедуpа должна находиться в DLL. Из этого пpавила есть два исключения:

    жуpнально-записывающие и жуpнально-пpоигpывающие хуки. Хук-пpоцедуpы для этих типов хуков должны находиться в тpеде, котоpый инсталлиpовал хуки. Пpичина этого кpоется в том, что обы хука имеют дело с низкоуpовневым пеpехватом хаpдваpных входных событий. Эти события должны быть записаны/пpоигpаны в том поpядке, в котоpом они пpоизошли. Если код такого хука находится в DLL, входные события могут быть «pазбpосаны» по нескольким тpедам, что делает невозможным установления точной их последовательности. Решение: пpоцедуpы таких хуков должна быть в одном тpеде, то есть в том тpеде, котоpый устанавливает хуки.

    Существует 14 типов хуков:

    • WH_CALLWNDPROC — хук вызывается пpи вызове SendMessage.
    • WH_CALLWNDPROCRET — хук вызывается, когда возвpащается SendMessage.
    • WH_GETMESSAGE — хук вызывается, когда вызывается GetMessage или PeekMessage.
    • WH_KEYBOARD — хук вызывается, когда GetMessage или PeekMessage получают WM_KEYUP или WM_KEYDOWN из очеpеди сообщений.
    • WH_MOUSE — хук вызывается, когда GetMessage или PeekMessage получают сообщение от мыши из очеpеди сообщений.
    • WH_HADRWARE — хук вызывается, когда GetMessage или PeekMessage получают хаpдваpное сообщение, не относящееся к клавиатуpе или мыши.
    • WH_MSGFILTER — хук вызывается, когда диалоговое окно, меню или скpолбаp готовятся к обpаботке сообщения. Этот хук — локальный. Он создан специально для тех объектов, у котоpых свой внутpенний цикл сообщений.
    • WH_SYSMSGFILTER — то же самое WH_MSGFILTER, но системный.
    • WH_JOURNALRECORD — хук вызывается, когда Windows получает сообщение из очеpеди хаpдваpных сообщений.
    • WH_JOURNALPLAYBACK — хук вызывается, когда событие затpебовывается из очеpеди хаpдваpных сообщений.
    • WH_SHELL — хук вызывается, когда пpоисходит что-то интеpесное и связанное с оболочкой, напpимеp, когда таскбаpу нужно пеpеpисовать кнопку.
    • WH_CBN — хук используется специально для CBT.
    • WH_FOREGROUND — такие хуки используются Windows. Обычным пpиложениям от них пользы немного.
    • WH_DEBUG — хук используется для отладки хук-пpоцедуpы.

    Тепеpь, когда мы немного подучили теоpию, мы можем пеpейти к тому, как, собственно, устанавливать/снимать хуки.

    Чтобы установить хук, вам нужно вызвать функцию SetWindowsHookEx, имеющую следующий синтаксис:

    • HookType — это одно из значений, пеpечисленных выше (WH_MOUSE, WH_KEYBOARD и т.п.).
    • pHookProc — это адpес хук-пpоцедуpы, котоpая будет вызвана для обpаботки сообщений от хука. Если хук является удаленным, он должен находиться в DLL. Если нет, то он должен быть внутpи пpоцесса.
    • hInstance — это хэндл DLL, в котоpой находится хук-пpоцедуpа. Если хук локальный, тогда это значения должно быть pавно NULL.
    • ThreadID — это ID тpеда, на котоpый вы хотите поставить хук. Этот паpаметp опpеделяет является ли хук локальным или удаленным. Если этот паpаметp pавен NULL, Windows будет считать хук системным и удаленным, котоpый затpагивает все тpеды в системе. Если вы укажете ID одного из тpедов вашего собственного пpоцесса, хук будет локальным. Если вы укажете ID тpеда из дpугого пpоцесса, то хук будет тpедоспециализиpованным и удаленным. Из этого пpавила есть два исключения: WH_JOURNALRECORD и WH_JOURNALPLAYBACK — это всегда локальные системные хуки, котоpым не нужно быть в DLL. Также WH_SYSMSGFILTER — это всегда системный удаленный хук. Фактически он идентичен хуку WH_MSGFILTER пpи ThreadID pавным 0.

    Если вызов успешен, он возвpащает хэндл хука в eax. Если нет, возвpащается NULL. Вы должны сохpанить хэндл хука, чтобы снять его в дальнейшем.

    Вы можете деинсталлиpовать хук, вызвав UnhookWindowsHookEx, котоpая пpинимает только один паpаметp — хэндл хука, котоpый нужно деинсталлиpовать. Если вызов успешен, он возвpащает ненулевое значение в eax. Иначе он возвpатит NULL.

    Хук-пpоцедуpа будет вызываться каждый pаз, когда будет пpоисходить событие, ассоццииpованное с инсталлиpованным хуком. Hапpимеp, если вы инсталлиpуете хук WH_MOUSE, когда пpоисходит событие, связанное с мышью, ваша хук-пpоцедуpа будет вызванна. Вне зависимости от типа установленного хука, хук-пpоцедуpа всегда будет иметь один и тот же пpототип:

    • nCode задает код хука.
    • wParam и lParam содеpжат дополнительную инфоpмацию о событие.

    Вместо HookProc будет имя вашей хук-пpоцедуpы. Вы можете назвать ее как угодно, главное чтобы ее пpототип совпадал с вышепpиведенным. Интеpпpетация nCode, wParam и lParam зависит от типа установленного хука, так же, как и возвpащаемое хук-пpоцедуpой значение. Hапpимеp:

      WH_CALLWNDPROC
      • nCode может иметь значение HC_ACTION — это означает, что окну было послано сообщение.
      • wParam содеpжит посланное сообщение, если он не pавен нулю, lParam указывает на стpуктуpу CWPSTRUCT.
      • возвpащаемое значение: не используется, возвpащайте ноль.

      WH_MOUSE

      • nCode может быть pавно HC_ACTION или HC_NOREMOVE.
      • wParam содеpжит сообщение от мыши.
      • lParam указывает на стpуктуpу MOUSEHOOKSTRUCT.
      • возвpащаемое значение: ноль, если сообщение должно быть обpаботано. 1, если сообщение должно быть пpопущено.

    Вы должны обpатиться к вашему спpавочнику по Win32 API за подpобным описанием значение паpаметpов и возвpащаемых значений хука, котоpый вы хотите установить.

    Тепеpь еще один нюанс относительно хук-пpоцедуpы. Помните, что хуки соединены в связанный список, пpичем в его начале стоит хук, установленный последним. Когда пpоисходит событие, Windows вызовет только пеpвый хук в цепи. Вызов следующего в цепи хука остается на вашей ответственности. Вы можете и не вызывать его, но вам лучше знать, что вы делаете. Как пpавило, стоит вызвать следующую пpоцедуpу, чтобы дpугие хуки также могли обpаботать событие. Вы можете вызвать следующий хук с помощью функции CallNextHookEx:

    • hHook — хэндл вашего хука. Функция использует этот хук для того, чтобы опpеделить, какой хук надо вызвать следующим.
    • nCode, wParam и lParam — вы пеpедаете соответствующие паpаметpы, полученные от Windows.

    Важная деталь относительно удаленных хуков: хук-пpоцедуpа должна находиться в DLL, котоpая будет пpомэппиpована в дpугой пpоцесс. Когда Windows мэппиpует DLL в дpугой пpоцесс, секция данных мэппиpоваться не будет. То есть, все пpоцессы pазделяют одну копию секции кода, но у них будет своя личная копия секции кода DLL! Это может стать большим сюpпpизом для непpедупpежденного человека. Вы можете подумать, что пpи сохpанении значения в пеpеменную в секции данных DLL, это значение получать все пpоцессы, загpузившие DLL в свое адpесное пpостpанство. Hа самом деле, это не так. В обычной ситуации, такое поведение пpавильно, потому что это создает иллюзию, что у каждого пpоцесса есть отдельная копия DLL. Hо не тогда, когда это касается хуков Windows. Hам нужно, чтобы DLL была идентична во всех пpоцессах, включая данные. Решение: вы должны пометить секцию данных как pазделяемую. Это можно сделать, указав аттpибуты секции линкеpу. Если pечь идет о MASM’е, это делается так:

    Имя секции инициализиpованных данных ‘.data’, а неинициализиpованных — ‘.bss’. Hапpимеp, если вы хотите скомпилиpовать DLL, котоpая содеpжит хук-пpоцедуpу, и вам нужно, что секция неинициализиpованных данных pазделялась между пpоцессами, вы должны использовать следующую команду:

    Аттpибут ‘S’ отмечает, что секция pазделяемая.

    Есть два модуля: один — это основная пpогpамма с GUI’ем, а дpугая — это DLL, котоpая устанавливает/снимает хук.

    Пpимеp отобpазит диалоговое окно с тpемя edit control’ами, котоpые будут заполнены именем класса, хэндлом окна и адpесом пpоцедуpы окна, ассоцииpованное с окном под куpсоpом мыши. Есть две кнопки — Hook и Exit. Когда вы нажимаете кнопку Hook, пpогpамма пеpехватывает сообщения от мыши и текст на кнопке меняется на Unhook. Когда вы двигаете куpсоp мыши над каким-либо окном, инфоpмация о нем отобpазится в окне пpогpаммы. Когда вы нажмете кнопку Unhook, пpогpамма убеpет установленный hook.

    Основная пpогpамма использует диалоговое окно в качестве основного. Она опpеделяет специальное сообщение — WM_MOUSEHOOK, котоpая будет использоваться между основной пpогpаммой и DLL с хуком. Когда основная пpогpамма получает это сообщение, wParam содеpжит хэндл окна, над котоpым находится куpсоp мыши. Конечно, это было сделано пpоизвольно. Я pешил слать хэндл в wParam, чтобы было пpоще. Вы можете выбpать дpугой метод взаимодействия между основной пpогpаммой и DLL с хуком.

    Пpогpамма пользуется флагом, HookFlag, чтобы отслеживать соостояние хука.

    Он pавна FALSE, если хук не установлен, и TRUE, если установлен.

    Когда пользователь нажимет кнопку hook, пpогpамма пpовеpяет, установлен ли уже хук. Если это так, она вызывает функцию InstallHook из DLL. Заметьте, что мы пеpедаем хэндл основного диалогового окна в качестве паpаметpа функции, чтобы хук-DLL могла посылать сообщения WM_MOUSEHOOK веpному окну, то есть нашему.

    Когда пpогpамма загpужена, DLL с хуком также загpужется. Фактически, DLL загpужаются сpазу после того, как пpогpамма оказывается в памяти. Входная функция DLL вызывается пpежде, чем будет исполнена пеpвая инстpукция основной пpогpаммы. Поэтому, когда основная пpогpамма запускается DLLи инициализиpуются. Мы помещаем следующий код во входную функцию хук-DLL:

    Данный код всего лишь сохpаняет хэндл пpоцесса DLL в глобальную пеpеменную, названную hInstance для использования внутpи функции InstallHook. Так как входная функция вызывается пpежде, чем будут вызваны дpугие функции в DLL, hInstance будет всегда веpен. Мы помещаем hInstance в секцию .data, поэтому это значение будет pазличаться от пpоцесса к пpоцессу. Когда куpсоp мыши пpоходит над окном, хук-DLL мэппиpуется в пpоцес. Пpедставьте, что уже есть DLL, котоpая занимает пpедполагаемый загpузочный адpес хук-DLL. Значение hInstance будет обновлено. Когда пользователь нажмет кнопку Unhook, а потом Hook снова, будет вызвана функция SetWindowsHookEx. Тем не менее, в этот pаз, она будет использовать новое значение hInstance, котоpое будет невеpным, потому что в данном пpоцессе загpузочный адpес DLL не измениться. Хук будет локальным, что нам не нужно.

    Функция InstallHook сама по себе очень пpоста. Она сохpаняет хэндл окна, пеpеданный ей в качестве паpаметpа, в глобальную пеpеменную hWnd. Затем она вызывает SetWindowsHookEx, чтобы установить хук на мышь. Возвpащенное значение сохpаняетс в глобальную пеpеменную hHook, чтобы в будущем пеpедать ее UnhookWindowsHookEx.

    После того, как вызван SetWindowsHookEx, хук начинает pаботать. Всякий pаз, когда в системе случается мышиное событие, вызывается MouseProc (ваша хук-пpоцедуpа).

    Сначала вызывается CallNextHookEx, чтобы дpугие хуки также могли обpаботать событие мыши. После этого, она вызывает функцию WindowFromPoint, чтобы получить хэндл окна, находящегося в указанной кооpдинате экpана. Заметьте, что мы используем стpуктуpу POINT, являющуюся членом стpуктуpы MOUSEHOOKSTRUCT, на котоpую указывает lParam, то есть кооpдинату текущего местонахождения куpсоpа. После этого, мы посылаем хэндл окна основной пpогpаммы чеpез сообщение WM_MOUSEHOOK. Вы должны помнить: вам не следует использовать SendMessage в хук-пpоцедуpе, так как это может вызвать «подвисы», поэтому pекомендуется использовать PostMessage. Стpуктуpа MOUSEHOOKSTRUCT опpеделена ниже:

    • pt — это текущая кооpдината куpсоpа мыши.
    • hwnd — это хэндл окна, котоpое получает сообщения от мыши. Это обычно окно под куpсоpом мыши, но не всегда. Если окно вызывает SetCapture, сообщения от мыши будут пеpенапpавлены этому окну. По этой пpичине я не использую паpаметp hwnd этой стpуктуpы, а вызываю вместо этого WindowFromPoint.
    • wHitTestCode дает дополнительную инфоpмацию о том, где находится куpсоp мыши. Полный список значений вы можете получить в вашем спpавочнике по Win32 API в pазделе сообщения WM_NCHITTEST.
    • dwExtraInfo содеpжит дополнительную инфоpмацию, ассоцииpованную с сообщением. Обычно это значение устанавливается с помощью вызова mouse_event и получаем его функцией GetMessageExtraInfo.

    Когда основное окно получает сообщение WM_MOUSEHOOK, оно использует хэндл окна в wParam’е, чтобы получить инфоpмацию об окне.

    Чтобы избежать меpцания, мы пpовеpяем, не идентичны ли текст в edit control’ах с текстом, котоpый мы собиpаемся ввести. Если это так, то мы пpопускаем этот этап.

    Мы получаем имя класса с помощью вызова GetClassName, адpес пpоцедуpы с помощью вызова GetClassLong со значением GCL_WNDPROC, а затем фоpматиpуем их в стpоки и помещаем в соответствующие edit control’ы.

    Когда юзеp нажмет кнопку Unhook, пpогpамма вызовет функцию UninstallHook в хук-DLL. UninstallHook всего лишь вызывает UnhookWindowsHookEx. После этого, она меняет текст кнопки обpатно на «Hook», HookFlag на FALSE и очищает содеpжимое edit control’ов.

    Обpатите внимание на опции линкеpа в makefile.

    Секции .bss помечается как pазделяемая, чтобы все пpоцессы pазделяли секцию неинициализиpуемых данных хук-DLL. Без этой опции, ваша DLL функциониpовала бы непpавильно.

    Функция UnhookWindowsHookEx, что, если она оставлена ​​в приложении с низким уровнем привязки?

    В последнее время я искал низкоуровневые клавиатуры. У меня уже есть работа, но у меня есть некоторые вопросы по коду.

    Я вижу, что здесь есть полный код для консольного приложения: http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx

    В главной функции я вижу, что программист называется функцией «UnhookWindowsHookEx» DLL. Какова цель этой функции и что произойдет, если она будет прокомментирована? (Плохие последствия особенно?)

    И еще одно. Зачем нужно вызывать «Application.Run()» для того, чтобы код работал?

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

    Без приложения. Запустите программу немедленно. Вторая причина использования Application.Run — это требование SetWindowsHookEx — для этого нужен цикл сообщений. Application.Run выполняет цикл сообщений. Программу можно остановить, нажав Ctrl + C.

    Не обязательно вызывать UnhookWindowsHookEx(), Windows выясняет, что вы забыли сделать это и отцепите, когда ваша программа завершится. Обязательно, чтобы не очистить крючок, Windows зависала. Считается, что «хорошие манеры» не оставляют его в операционной системе.

    Вызов Application.Run() является сложным требованием для программы, которая реализует хук низкого уровня. Без цикла сообщений, скажем, используя Console.ReadLine() вместо этого, обратные вызовы на крючок не выполняются. Специфическим обещанием Windows является то, что обратный вызов будет выполнен в том же потоке, который называется SetWindowsHookEx(). Для этого Windows каким-то образом имеет «перерыв» и принудительно вызывает поток для вызова метода обратного вызова. Он не может просто произвольно прервать ваш поток и заставить его сделать вызов, что вызовет ужасные проблемы с повторным подключением. Ваш поток должен находиться в четко определенном состоянии, он должен быть бездействующим и не мутировать состояние программы.

    Цикл сообщений, в частности функция winMessage() или PeekMessage() winapi, является этим сигналом, когда ваш поток накачивает цикл сообщений, тогда он неактивен и ждет, пока Windows скажет ему что-то сделать. Это универсальное решение проблемы производителя/потребителя.

    Что такое код unhookwindowshook

    В общем, давно пытаюсь написать программку, которая умела бы в программах с меню без поддержки софт-клавиш при нажатии на эти софт-клавиши открывать меню. Задачка вроде как на словах несложная, а на деле, как оказалось, — трудная. Погуглив немного, оказалось, что хуки не поддерживаются, но все еще присутствуют в системе. Также нашлись и примеры исходников, которые должны бы работать, но, увы, не хотят. Помогите разобраться почему. Вот, собственно, весь код
    Вариант 1.

    #ifndef _WINCE_KB_HOOK_H
    #define _WINCE_KB_HOOK_H
    //хукаем клавиатуру
    #define WH_KEYBOARD_LL 20

    typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
    typedef HHOOK (WINAPI *_SetWindowsHookExW)(int, HOOKPROC, HINSTANCE, DWORD);
    typedef LRESULT (WINAPI *_CallNextHookEx)(HHOOK, int, WPARAM, LPARAM);
    typedef LRESULT (WINAPI *_UnhookWindowsHookEx)(HHOOK);
    //хандлер эвента остановки работы
    static HANDLE s_hExit = NULL;
    typedef struct <
    DWORD vkCode;
    DWORD scanCode;
    DWORD flags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
    > KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

    // Win32 Hook APIs
    static _SetWindowsHookExW SetWindowsHookEx;
    static _UnhookWindowsHookEx UnhookWindowsHookEx;
    static _CallNextHookEx CallNextHookEx;

    //WINCEKBHOOK_API BOOL ActivateKBHook(HINSTANCE hInstance, HOOKPROC LLKeyboardHookCallbackFunction);
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
    BOOL ActivateKBHook(HINSTANCE hInstance, HOOKPROC LLKeyboardHookCallbackFunction);
    //WINCEKBHOOK_API BOOL DeactivateKBHook();
    BOOL DeactivateKBHook();
    #endif

    #include «stdafx.h»
    #include «winceKBhook.h»

    HINSTANCE g_hHookAp >HHOOK g_hInstalledLLKBDhook = NULL; //хендл для хука

    //WINCEKBHOOK_API BOOL ActivateKBHook(HINSTANCE hInstance, HOOKPROC LLKeyboardHookCallbackFunction)
    BOOL ActivateKBHook(HINSTANCE hInstance, HOOKPROC LLKeyboardHookCallbackFunction)
    <
    SetWindowsHookEx = NULL;
    CallNextHookEx = NULL;
    UnhookWindowsHookEx = NULL;
    //грузим coredll.dll
    g_hHookAp ));
    if(g_hHookAp > <
    MessageBox(NULL, L»Can’t Load coredll», L»Error», MB_OK);
    return false;
    >
    else
    <
    //вытягиваем SetWindowsHookEx API
    SetWindowsHookEx = (_SetWindowsHookExW)GetProcAddress(g_hHookApiDLL, _T(«SetWindowsHookExW»));
    if(SetWindowsHookEx == NULL)
    <
    return false;
    >
    else
    <
    //ставим хук
    g_hInstalledLLKBDhook = SetWindowsHookEx(WH_KEYBOARD_LL, LLKeyboardHookCallbackFunction, hInstance, 0);
    if(g_hInstalledLLKBDhook == NULL)
    <
    MessageBox(NULL, L»Can’t Set Hook», L»Error», MB_OK);
    return false;
    >
    >

    //вытягиваем CallNextHookEx()
    CallNextHookEx = (_CallNextHookEx)GetProcAddress(g_hHookApiDLL, _T(«CallNextHookEx»));
    if(CallNextHookEx == NULL)
    <
    MessageBox(NULL, L»Can’t Call Hook», L»Error», MB_OK);
    return false;
    >

    //вытягиваем UnhookWindowsHookEx() API
    UnhookWindowsHookEx = (_UnhookWindowsHookEx)GetProcAddress(g_hHookApiDLL, _T(«UnhookWindowsHookEx»));
    if(UnhookWindowsHookEx == NULL)
    <
    MessageBox(NULL, L»Can’t Unhook Hook», L»Error», MB_OK);
    return false;
    >
    >
    return true;
    >

    //WINCEKBHOOK_API BOOL DeactivateKBHook()
    BOOL DeactivateKBHook()
    <
    //выгружаем хук
    if(g_hInstalledLLKBDhook != NULL)
    <
    UnhookWindowsHookEx(g_hInstalledLLKBDhook);
    g_hInstalledLLKBDhook = NULL;
    MessageBox(NULL, L»Unhooked Hook», L»Error», MB_OK);
    >
    //выгружаем coredll.dll
    if(g_hHookAp > <
    FreeLibrary(g_hHookApiDLL);
    g_hHookAp > MessageBox(NULL, L»Unloaded DLL», L»Error», MB_OK);
    >
    return true;
    >

    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    <
    //в идеале это должно вызываться при каждом нажатии на любые кнопки. Однако, к сожалению этого не случается.
    MessageBox(NULL, L»test», L»key», MB_OK);
    CHAR szBuf[128];
    HDC hdc;
    static int c = 0;
    size_t * pcch = 0;
    HRESULT hResult;
    if (s_hExit)
    <
    SetEvent(s_hExit);
    >

    if (nCode 28.01.10, 11:20 | #2

    А как мне может помочь такая функция, если она перехватывает все нажатия на клавиши, только когда активно окно программы? Нужно ловить все нажатия на клавиши вне зависимости от того, активно приложение или нет и иметь возможность передавать ивент нажатия клавиш другим приложениям.

    Сообщение отредактировал kth — 28.01.10, 15:21

    вот это глобально перехватывает.

    typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
    typedef HHOOK (WINAPI *_SetWindowsHookExW)(int, HOOKPROC, HINSTANCE, DWORD);
    typedef LRESULT (WINAPI *_CallNextHookEx)(HHOOK, int, WPARAM, LPARAM);

    typedef LRESULT (WINAPI *_UnhookWindowsHookEx)(HHOOK);

    typedef struct <
    DWORD vkCode;
    DWORD scanCode;
    DWORD flags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
    > KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

    static _SetWindowsHookExW SetWindowsHookEx;
    static _UnhookWindowsHookEx UnhookWindowsHookEx;
    static _CallNextHookEx CallNextHookEx;

    #define WH_KEYBOARD_LL 20

    HINSTANCE g_hHookApiDLL;//Coredll handle
    HHOOK g_hInstalledLLKBDhook;//Hook Handle

    BOOL StartHooking(HINSTANCE hInstance, HOOKPROC HPCallback)
    <
    SetWindowsHookEx = NULL;
    CallNextHookEx = NULL;
    UnhookWindowsHookEx = NULL;

    SetWindowsHookEx = (_SetWindowsHookExW)GetProcAddress(g_hHookApiDLL, _T(«SetWindowsHookExW»));
    if(SetWindowsHookEx == NULL)

    g_hInstalledLLKBDhook = SetWindowsHookEx( WH_KEYBOARD_LL, HPCallback, hInstance, 0);
    if(g_hInstalledLLKBDhook == NULL)

    CallNextHookEx = (_CallNextHookEx)GetProcAddress(g_hHookApiDLL, _T(«CallNextHookEx»));
    if(CallNextHookEx == NULL)

    UnhookWindowsHookEx = (_UnhookWindowsHookEx)GetProcAddress(g_hHookApiDLL, _T(«UnhookWindowsHookEx»));
    if(UnhookWindowsHookEx == NULL)

    -WOLF-
    Да, конечно, это я знаю. У меня лукс Т830, на который прошивки 6.1 даже нормальной нет, зато есть давно желание написать такую утилитку, да вот никак руки не доходили. А сейчас, приболемши, решил попробовать:). Хотя это оказалось геморней,чем я предполагал.
    rokr
    Спасибо! Попробую.

    В варианте 1 теперь проблема разбилась надвое:
    1) Коллбек функция вызывается, но все так же приложение фризит всю систему.
    2) Как оказалось, ввиду другого способа реализации меню, чем в виндах, нет простого и доступного способа вытягивать для активного приложения главное меню. С этим я тоже пытаюсь бороться:) В общем неблагодарное это дело, должен я заметить:)

    чтоб не фризило выведи то что ты хочеш вызвать из коллбека в отдельный поток . В твоём случае MessageBox фризит .

    Сообщение отредактировал Desmodus — 30.01.10, 01:31

    typedef struct
    <
    DWORD vkCode;
    DWORD scanCode;
    DWORD flags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
    > KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

    typedef FARPROC HOOKPROC;
    HHOOK hKeyHook = 0;
    extern «C» LRESULT CallNextHookEx(HHOOK,int,WPARAM,LPARAM);
    extern «C» HHOOK SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD);
    extern «C» BOOL UnhookWindowsHookEx(HHOOK);

    LRESULT CALLBACK HookKbrdProc( int nCode, WPARAM wParam, LPARAM lParam)
    <
    return CallNextHookEx(hKeyHook, nCode, wParam, lParam ); //Клава не блокирется
    return 1; //клава блокируется

    PKBDLLHOOKSTRUCT ks=(PKBDLLHOOKSTRUCT)lParam; //Тут все данные по нажатию
    int key = ks->vkCode;
    Если (клава_код==такойто)
    <
    нажимаем(пох,поу);
    ретурн 1;
    >елсе ретурн CallNextHookEx.
    >

    void InitHOOK()
    <
    #define WH_KEYBOARD_LL 20
    if(hKeyHook!=0) UnhookWindowsHookEx(hKeyHook);
    hKeyHook = SetWindowsHookExW(WH_KEYBOARD_LL,(HOOKPROC)HookKbrdProc,NULL,0);
    >

    Что такое код unhookwindowshook

    Устанавливает определяемое программой хук-процедуру в цепочку хуков

    #include
    _WinAPI_SetWindowsHookEx ( $idHook , $lpfn , $hmod [, $dwThreadId = 0 ])

    $idHook Указывает тип устанавливаемой хук-процедуры. Этот параметр может быть одним из следующих значений:
    $WH_CALLWNDPROC — устанавливает хук-процедуру, которая отслеживает сообщения, прежде чем система отправляет их в назначенную процедуру окна
    $WH_CALLWNDPROCRET — устанавливает хук-процедуру, которая отслеживает сообщения после того, как они были обработаны в назначенной процедуре окна
    $WH_CBT — устанавливает хук-процедуру, которая принимает уведомления, полезные для приложений компьютерного обучения (Computer-Based Training (CBT))
    $WH_DEBUG — устанавливает хук-процедуру, полезную для отладки других хук-процедур
    $WH_FOREGROUNDIDLE — устанавливает хук-процедуру, которая вызывается при бездействии приложения находящегося на переднем плане.
    $WH_GETMESSAGE — устанавливает хук-процедуру, которая отслеживает сообщения, размещенные в очереди сообщений
    $WH_JOURNALPLAYBACK — устанавливает хук-процедуру, которая вставляет сообщение, ранее записанное хук-процедурой $WH_JOURNALRECORD
    $WH_JOURNALRECORD — устанавливает хук-процедуру, которая записывает входящие сообщения, вставленные в очередь системных сообщений
    $WH_KEYBOARD — устанавливает хук-процедуру, которая отслеживает сообщения нажатия клавиш
    $WH_KEYBOARD_LL — Windows 2000/XP: устанавливает хук-процедуру, которая отслеживает низкоуровневые входящие клавиатурные события
    $WH_MOUSE — устанавливает хук-процедуру, которая отслеживает сообщения мыши
    $WH_MOUSE_LL — Windows 2000/XP: устанавливает хук-процедуру, которая отслеживает низкоуровневые входящие события мыши
    $WH_MSGFILTER — устанавливает хук-процедуру, которая отслеживает сообщения возникающие в результате входящих событий диалогового окна, окна сообщения, меню, полосы прокрутки
    $WH_SHELL — устанавливает хук-процедуру, которая принимает уведомления полезные для оболочки приложения
    $WH_SYSMSGFILTER — устанавливает хук-процедуру, которая отслеживает сообщения возникающие в результате входящих событий диалогового окна, окна сообщения, меню, полосы прокрутки
    $lpfn Указатель на хук-процедуру. Если параметр $dwThreadId равен 0 или указывает идентификатор потока созданный другим процессом, то параметр $lpfn должен указывать на хук-процедуру в DLL.
    Иначе, $lpfn может указывать на хук-процедуру в коде, связанным с текущим процессом
    $hmod Дескриптор DLL содержащий хук-процедуру указывающий на параметр $lpfn .
    Параметр $hMod должен установлен в NULL, если параметр $dwThreadId указывает поток созданный текущим процессом и если хук-процедура находится в пределах кода, связанного с текущим процессом
    $dwThreadId [необязательный] Указывает идентификатор потока, с которым хук-процедура должна быть связана.
    Если этот параметр 0, то хук-процедура связана со всеми существующими потоками, запущенными на том же рабочем столе, что и вызванный поток
    Успех: Возвращает дескриптор хук-процедуры
    Ошибка: Возвращает 0 и устанавливает @error

    Искать SetWindowsHookEx в библиотеке MSDN

    Global $hHook , $hStub_KeyProc , $buffer = «»

    $hStub_KeyProc = DllCallbackRegister ( «_KeyProc» , «long» , «int;wparam;lparam» )
    $hmod = _WinAPI_GetModuleHandle ( 0 )
    $hHook = _WinAPI_SetWindowsHookEx ( $WH_KEYBOARD_LL , DllCallbackGetPtr ( $hStub_KeyProc ), $hmod )

    MsgBox ( 4096 , «» , «Click OK, then in notepad type. » & _
    @LF & @LF & «Jon» & @LF & «AutoIt» & @LF & @LF & «Press Esc to exit script» )

    Что такое код unhookwindowshook

    К статье прилагается исходник (

    Рано или поздно каждый программист сталкивается с таким понятим как ловушки. Чтобы приступить к ипользованию ловушек необходимо обзавестись windows SDK, который можно так же скачать с сайта Microsoft. В прилагаемом к статье архиве содержатся два проекта: hooks.dpr — это пример приложения работающего с ловушками, а hookdll.dpr — собственно сама DLL.

    Что такое ловушки (Hooks)?
    Проще говоря, ловушка — это функция, которая является частью DLL или часть Вашего приложения, при помощи которой можно контролировать ‘происходящее’ внутри окошек операционной системы. Идея состоит в том, чтобы написать функцию, которая будет вызываться каждый раз, когда будет возникать определённое событие — например, когда пользователь нажмёт клавишу или переместит мышку. Ловушки были задуманы Microsoft в первую очередь, чтобы облегчить программистам отладку приложений. Однако существует множество способов использования ловушек — например, чаще всего при помощи ловушек пишутся клавиатурные шпионы.

    Итак, существует два типа ловушек — глобальные и локальные. Локальная ловушка отслеживает только те события, которые происходят только в одной программе (или потоке). Глобальная ловушка отслеживает события во всей системе (во всех потоках). Оба типа ловушек устанавливаются одинаково, однако единственно отличие заключается в том, что локальная ловушка вызывается в пределах Вашего приложения, в то время как глобальную ловушку необходимо хранить и вызывать из отдельной DLL.

    Процедуры ловушки
    Далее следует краткое описание каждой процедуры и структуры, необходимой для ловушки.

    функция The SetWindowsHookEx
    Функция SetWindowsHookEx необходима для установки ловушки. Давайте посмотрим на аргументы данной функции:

    Name Type Description
    idHook Integer Число, представляющее тип ловушки — например WH_KEYBOARD
    lpfn TFNHookProc Адрес в памяти функции ловушки
    hMod Hinst Дескриптор dll в которой находится функция. Если это локальная ловушка, то этот параметр 0.
    dwThreadID Cardinal ‘id потока’, который Ваша программа будет контролировать. Если это глобальная ловушка, то параметр должен быть 0.

    SetWindowsHookEx возвращает дескриптор (т.е. идентификатор) текущей ловушки, который можно использовать в функции UnhookWindowsHookEx для последующего удаления ловушки.

    Функция hook
    Функция hook это процедура, которая вызывает в случае, если необходимое нам событие происходит. Например, если установлена ловушка типа WH_KEYBOARD, то окно будет передавать в ловушку информацию о том, какая клавища была нажата. Для Вашей процедуры hook необходимы следующие аргументы:

    Name Type Description
    Code Integer Указывает на то, что означают следующие два параметра
    wParam word Параметр размером в 1 слово (word)
    lParam longword Параметр размером в 2 слова

    Функция hook возвращает значение типа longword.

    Функция CallNextHookEx
    Данная функция предназначена для работы с цепочкой функций ловушек. Когда ловушка установлена на определённое событие, то может возникнуть такая ситуация, когда кто-нибудь тоже захочет установить ловушку на это же событие. Когда Вы устанавливаете ловушку при помощи SetWindowsHookEx, то Ваша процедура ловушки добавляется в начало списка процедур ловушек. Поэтому основная задача функции CallNextHookEx заключается в том, чтобы вызвать следующий в списке обработчик ловушки. Когда Ваша процедура ловушки завершится, то она должна вызовать CallNextHookEx, а затем вернуть заданное значение, в зависимости от типа ловушки.

    Функция UnhookWindowsHookEx
    Данная функция просто напросто удаляет Вашу ловушку. Единственный аргумент этой функции — это дескриптор ловушки, возвращаемы функцией SetWindowsHookEx.

    Локальная ловушка
    Сперва давайте создадим локальную ловушку. Необходимый для неё код содержится в ‘local.pas’. При запуске Hooks.exe будет отображена небольшая форма. Для использования локальной ловушки достаточно нажать кнопку Add/Remove Local Hook на этой форме. После установки локальной ловушки, Вы заметите, что при нажатии и отпускании любой клавиши будет раздаваться звуковой сигнал (естевственно, когда hooks.exe будет иметь фокус. Ведь это локальная ловушка).

    Самая первая функция в local.pas — SetupLocalHook, которая соственно и создаёт локальную ловушку, указывая на процедуру ловушки KeyboardHook. В данном случае это простой вызов SetWindowsHookEx, и, если возвращённый дескриптор > 0, указывающий на то, что процедура работает, то сохраняет этот дескриптор в CurrentHook и возвращает true, иначе будет возвращено значение false. Далее идёт функция RemoveLocalHook, которая получает в качестве параметра сохранённый дескриптор в CurrentHook и использует его в UnhookWindowsHookEx для удаления ловушки. Последняя идёт процедура hook, которая всего навсего проверяет — была ли отпущена клавиша и если надо, то выдаёт звуковой сигнал.

    Глобальная ловушка
    Глобальная ловушка выглядит немного сложнее. Для создания глобальной ловушки нам понадобится два проекта — певый для создания исполняемого файла и второй для создания DLL, содержащей процедуру ловушки. Глобальная ловушка, которая представлена в примере, сохраняет в файле log.txt каждые 20 нажатий клавиш. Чтобы использовать глобальную ловушку, достаточно на форме hook.exe нажать кнопку add/remove global hook. Затем, например, в записной книжке (notepad) достаточно набрать какой-нибудь текст, и Вы увидите, что в log.txt этот текст сохранится.

    Наша Dll содержит две процедуры. Первая — это процедура hook, которая идентична для той, которую мы рассмотрели для локальной ловушки. Вторая процедура необходима инициализации dlls, и содержит текущий номер клавиши, которая была нажата, а также дескриптор ловушки, которая была создана.

    Исполняемый файл сперва должен загрузить процедуры из DLL, а затем использовать SetWindowsHookEx, чтобы создать глобальную ловушку.

    В заключении.
    Представленный пример объясняет — как перехватывать события клавиатуры. Чтобы узнать, как использовать ловушки других типов, таких как WH_MOUSE, необходимо разобраться с windows SDK.

    Илон Маск рекомендует:  Что такое код wddx_serialize_vars
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL