
GUI гуру
   
Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е
Репутация: 25 Всего: 62
|
| Цитата | ЧТО ТАКОЕ ХУКИ... Фирменное блюдо этого урока - хуки! В кухне Microsoft Windows хуком называется механизм перехвата особой функцией событий (таких как сообщения, ввод с мыши или клавиатуры) до того, как они дойдут до приложения. Эта функция может затем реагировать на события и, в некоторых случаях, изменять или отменять их. Функции, получающие уведомления о событиях, называются хук-функциями и различаются по типам перехватываемых ими событий. Пример - хук-функция для перехвата всех событий мыши или клавиатуры. Чтобы Windows смогла вызывать хук-функцию, эта функция должна быть установлена - то есть, прикреплена к хуку (например, к клавиатурному хуку). Прикрепление одной или нескольких хук-функций к какому-нибудь хуку называется установкой хука. Если к одному хуку прикреплено несколько хук-функций, Windows реализует очередь функций (цепочку хуков), причем функция, прикрепленная последней, оказывается в начале очереди, а самая первая функция - в ее конце.
Когда к хуку прикреплена одна или более хук-функций и происходит событие, приводящее к срабатыванию хука, Windows вызывает первую функцию из очереди хук-функций. Это действие называется вызовом хука. К примеру, если к хуку CBT прикреплена функция и происходит событие, после которого срабатывает хук (допустим, идет создание окна), Windows вызывает CBT-хук, то есть первую функцию из его очереди.
Хуки предоставляют мощные возможности для приложений 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).
Симулировать мышиный и клавиатурный ввод (WH_JOURNALPLAYBACK). Хуки - единственный надежный способ симуляции этих действий. Если попытаться имитировать их через посылку сообщений, не будет происходить обновление состояния клавиатуры или мыши во внутренних структурах Windows, что может привести к непредсказуемому поведению. Если для воспроизведения клавиатурных или мышиных событий используются хуки, эти события обрабатываются в точности так, как и настоящий ввод с клавиатуры или мыши.
Сделать возможным использование CBT приложениями Windows (WH_CBT). Хук WH_CBT значительно облегчает разработку CBT-приложений.
Рассмотрим подробнее типы хуков:
WH_CALLWNDPROC. Windows вызывает этот хук при каждом вызове функции SendMessage. Фильтрующей функции передается код хука, показывающий, была ли произведена посылка сообщения из текущего потока, а также указатель на структуру с информацией о сообщении. Структура CWPSTRUCT описана следующим образом:
typedef struct tagCWPSTRUCT { LPARAM lParam; WPARAM wParam; DWORD message; HWND hwnd; } CWPSTRUCT, *PCWPSTRUCT, NEAR *NPCWPSTRUCT, FAR *LPCWPSTRUCT;
Хук-функции могут обработать сообщение, но не могут изменять его. Сообщение затем отсылается той функции, которой и предназначалось. Этот хук использует значительное количество системных ресурсов, особенно, когда он установлен с системной областью видимости, поэтому используйте его только в целях отладки.
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, которая описана следующим образом:
typedef struct tagCBTACTIVATESTRUCT { BOOL fMouse; // TRUE, если активация наступила в результате // мышиного клика; иначе FALSE. HWND hWndActive; // Содержит дескриптор окна, активного // в настоящий момент. } CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;
Windows вызывает хук WH_CBT с HCBT_CREATEWND при создании окна. Когда хук установлен как локальный, это окно должно создаваться потоком, на который установлен хук. Хук WH_CBT вызывается до того, как Windows пошлет новому окну сообщения WM_GETMINMAXINFO, WM_NCCREATE, или WM_CREATE. Таким образом, хук-функция может запретить создание окна, вернув TRUE. В параметре wParam содержится дескриптор создаваемого окна. В lParam - указатель на следующую структуру.
struct CBT_CREATEWND { struct tagCREATESTRUCT *lpcs; // Данные для создания // нового окна. HWND hwndInsertAfter; // Хэндл окна, после которого будет // добавлено это окно (Z-order). } CBT_CREATEWND, *LPCBT_CREATEWND;
Хук-функция может изменить значение hwndInsertAfter или значения в lpcs. Windows вызывает хук WH_CBT с HCBT_DESTROYWND перед уничтожением какого-либо окна. Если хук является локальным, это окно должно принадлежать потоку, на который установлен хук. Windows вызывает хук WH_CBT до посылки сообщения WM_DESTROY. Если хук-функция вернет TRUE, окно не будет уничтожено. Параметр wParam содержит дескриптор уничтожаемого окна. В lParam находится 0L.
Windows вызывает хук WH_CBT с HCBT_MINMAX перед минимизацией или максимизацией окна. Когда хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если хук-функция вернет TRUE, действие будет отменено. В wParam передается дескриптор окна, которое готовится к максимизации/минимизации. lParam содержит одну из SW_*-констант, определенных в WINUSER.H и описывающих операцию над окном.
Windows вызывает хук WH_CBT с HCBT_MOVESIZE перед перемещением или изменением размеров окна, сразу после того, как пользователь закончил выбор новой позиции или размеров окна. Если хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если хук-функция вернет TRUE, действие будет отменено. В wParam передается дескриптор перемещаемогоизменяемого окна. lParam содержит LPRECT, который указывает на новые координаты окна.
Windows вызывает хук WH_CBT с HCBT_SYSCOMMAND во время обработки системной команды. Если хук установлен как локальный, окно, чье системное меню вызвало данное событие, должно принадлежать потоку, на который установлен хук. Хук 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 Вертикальная прокрутка.
Windows вызывает хук WH_CBT с HCBT_CLICKSKIPPED при удалении события от мыши из входной очереди потока, в случае, если установлен хук мыши. Windows вызовет системный хук, когда из какой-либо входной очереди будет удалено событие от мыши и в системе установлен либо глобальный, либо локальный хук мыши. Данный код передается только в том случае, если к хуку WH_MOUSE прикреплена хук-функция. Несмотря на свое название, HCBT_CLICKSKIPPED генерируется не только для пропущенных событий от мыши, но и в случае, когда событие от мыши удаляется из системной очереди. Его главное назначение - установить хук WH_JOURNALPLAYBACK в ответ на событие мыши. (За дополнительной информацией обратитесь к секции "WM_QUEUESYNC".) В wParam передается идентификатор сообщения мыши - например, WM_LBUTTONDOWN или любое из сообщений WM_?BUTTON*. lParam содержит указатель на структуру MOUSEHOOKSTRUCT, которая описана следующим образом:
typedef struct tagMOUSEHOOKSTRUCT { POINT pt; // Позиция курсора мыши в координатах экрана HWND hwnd; // Окно, получающее сообщение UINT wHitTestCode; // Результат проверки координат (hit-testing) DWORD dwExtraInfo; // Доп.информация о сообщении } MOUSEHOOKSTRUCT, FAR *LPMOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
Windows вызывает хук WH_CBT с HCBT_KEYSKIPPED при удалении клавиатурного события из системной очереди, в случае, если установлен клавиатурный хук. Windows вызовет системный хук, когда из какой-либо входной очереди будет удалено событие от клавиатуры и в системе установлен либо глобальный, либо локальный клавиатурный хук. Данный код передается только в том случае, если к хуку WH_KEYBOARD прикреплена хук-функция. Несмотря на свое название, HCBT_KEYSKIPPED генерируется не только для пропущенных клавиатурных событий, но и в случае, когда клавиатурное событие удаляется из системной очереди. Его главное назначение - установить хук WH_JOURNALPLAYBACK в ответ на клавиатурное событие. (За дополнительной информацией обратитесь к секции "WM_QUEUESYNC".) В wParam передается виртуальный код клавиши - то же самое значение, что и в wParam функций GetMessage или PeekMessage для сообщений WM_KEY*. lParam содержит то же значение, что и lParam функций GetMessage или PeekMessage для сообщений WM_KEY*.
Часто приложение интерактивного обучения (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-приложение получает такое сообщение, оно может выполнить необходимые действия, например, послать главному приложению серию клавиатурных нажатий.
Windows вызывает хук WH_CBT с HCBT_SETFOCUS, когда Windows собирается передать фокус ввода какому-либо окну. Когда хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Если хук-функция вернет TRUE, фокус ввода не изменится. В wParam передается дескриптор окна, получающего фокус ввода. lParam содержит дескриптор окна, теряющего фокус ввода.
Windows вызывает хук WH_CBT с HCBT_QS когда из системной очереди удаляется сообщение WM_QUEUESYNC, в то время как происходит изменение размеров или перемещение окна. Ни в каком другом случае этот хук не вызывается. Если хук установлен как локальный, это окно должно принадлежать потоку, на который установлен хук. Оба параметра - и wParam, и lParam - содержат ноль.
WH_DEBUG. Windows вызывает этот хук перед вызовом какой-либо хук-функции. Фильтры не могут изменять значения, переданные этому хуку, но могут предотвратить вызов хук-функции, возвратив ненулевое значение. В wParam передается идентификатор вызываемого хука, например, WH_MOUSE. lParam содержит указатель на следующую структуру:
typedef struct tagDEBUGHOOKINFO { DWORD idThread; // Идентификатор текущего потока LPARAM reserved; LPARAM lParam; // lParam для хук-функции WPARAM wParam; // wParam для хук-функции int code; } DEBUGHOOKINFO, *PDEBUGHOOKINFO, NEAR *NPDEBUGHOOKINFO, FAR* LPDEBUGHOOKINFO;
WH_FOREGROUNDIDLE. Windows вызывает этот хук, когда к текущему потоку не поступает пользовательский ввод для обработки. Когда хук установлен как локальный, Windows вызывает его только при условии отсутствия пользовательского ввода у потока, к которому прикреплен хук. Данный хук является уведомительным, оба параметра - и wParam, и lParam - равны нулю.
WH_GETMESSAGE. Windows вызывает этот хук перед выходом из функций GetMessage и PeekMessage. Фильтрующие функции получают указатель на структуру с сообщением, которое затем (вместе со всеми изменениями) посылается приложению, вызвавшему GetMessage или PeekMessage. В lParam находится указатель на структуру MSG:
typedef struct tagMSG { /* msg */ HWND hwnd; // Окно, чья Winproc получит сообщение UINT message; // Номер сообщения WPARAM wParam; LPARAM lParam; DWORD time; // Время посылки сообщения POINT pt; // Позиция указателя мыши (в экранных координатах) // для этого сообщения } MSG;
WH_HARDWARE. Этот хук в Win32 пока не реализован.
Регистрационные хуки используются для записи и воспроизведения событий. Они могут устанавливаться только как системные, и, следовательно, должны использоваться как можно реже. Эти хуки воздействуют на все приложения Windows; хотя десктоп и не позволяет такого другим хукам, регистрационные хуки могут записывать и воспроизводить последовательности событий и от десктопа, и для десктопа. Другой побочный эффект регистрационных хуков в том, что все системные входные очереди проходят через один поток, который установил такой хук.
В Win32 предусмотрена специальная последовательность действий, с помощью которой пользователь может убрать регистрационный хук (например, в случае, если он завесил систему). Windows отключит записывающий или воспроизводящий регистрационный хук, когда пользователь нажмет CTRL+ESC, ALT+ESC, или CTRL+ALT+DEL. Windows оповестит приложение, установившее этот хук, посылкой ему сообщения 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.
Windows вызывает хук WH_JOURNALRECORD с HC_ACTION при удалении события из системной очереди. Этот код сигнализирует хук-функции о том, что это событие является нормальным. В lParam при этом передается указатель на структуру EVENTMSG. Обычная процедура записи состоит в сохранении всех пришедших хуку структур EVENTMSG в памяти или на диске. Структура EVENTMSG описана в WINDOWS.H следующим образом:
typedef struct tagEVENTMSG { UINT message; UINT paramL; UINT paramH; DWORD time; HWND hwnd; } EVENTMSG; typedef struct tagEVENTMSG *PEVENTMSG, NEAR *NPEVENTMSG, FAR *LPEVENTMSG;
Элемент 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
HC_SKIP
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
HC_NOREMOVE
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 не будут вызваны.
|
| Цитата | Чтобы воспользоваться определенным типом хуков, необходимо создать хук-функцию и использовать функцию SetWindowsHookEx для того, чтобы хук-функцию включить в очередь. У хук-функции следующий вид:
LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, LPARAM lParam ); nCode - код хука. Это целое значение, которое передает функции дополнительную информацию. К примеру, код хука может описывать событие, которое привело к срабатыванию хука.
Параметры wParam и lParam передают информацию хук-функцияующим функциям. У каждого хука значения wParam и lParam различаются.
Функция SetWindowsHookEx добавляет хук-функцию в начало цепочки хуков.
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ); idHook - целочисленный код, описывающий хук, к которому будет прикреплена хук-функцияующая функция.
lpfn - адрес функции-хук-функцияа. Эта функция должна быть описана как экспортируемая включением ее в секцию EXPORTS файла определения приложения или библиотеки динамической линковки (DLL), или использованием соответствующих опций компилятора.
hMod - дескриптор модуля, содержащего хук-функцияующую функцию. В Win32 (в отличие от Win16), этот параметр должен быть NULL при установке хука на поток (см. ниже). При установке хука для всей системы или для потока в другом процессе, нужно использовать дескриптор DLL, содержащей функцию-хук-функция.
dwThreadId - идентификатор потока, для которого устанавливается хук. Если этот идентификатор ненулевой, установленная хук-функция будет вызываться только в контексте указанного потока. Если идентификатор равен нулю, установленная функция имеет системную область видимости и может быть вызвана в контексте любого потока в системе. Приложение или библиотека могут использовать функцию GetCurrentThreadId для получения идентификатора текущего потока.
Если Вы уже прочитали все написанное выше, у Вас наверняка возник вопрос: чем отличается глобальный хук от поточного. Глобальный хук отслеживает сообщения от всех потоков на том же рабочем столе, что и вызывающий хук поток. Естественно, поточный хук отслеживает сообщения только одного потока. Глобальная хук-функция может быть вызвана любым приложением на том же рабочем столе, что и вызывающий поток, то есть функция должна быть в отдельной DLL. Поточная хук-функция вызывается только в контексте вызывающего потока. Если приложение добавляет хук-функцию для одного из его потоков, хук-функция может быть как в том же модуле, где и остальной код приложения, так и в DLL. Если же приложение добавляет хук-функцию для потока другого приложения, хук-функция должна быть в DLL.
Когда происходит событие, которое отслеживается определенным типом хуков, система вызывает хук-функцию стоящую первую в цепочке. Каждая хук-функцияв цепочке определяет когда передать событие следующей хук-функции. Хук-функция передает событие следующей хук-функции при помощи вызова функции CallNextHookEx.
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam ); Первый параметр - это значение, возвращенное функцией SetWindowsHookEx. В настоящее время Windows игнорирует это значение, но в будущем это может измениться.
Остальные три параметра такие же, как в функции SetWindowsHookEx.
Функция CallNextHookEx возвращает значение, возвращаемое следующей хук-функцией в цепочке.
Еще одна функция, которую мы рассмотрим, - UnhookWindowsHookEx. Данная функция удаляет хук-функцию из цепочки хуков.
BOOL UnhookWindowsHookEx( HHOOK hhk // handle to hook procedure ); Единственный параметр этой функции - дескриптор хука, который необходимо убрать.
Функция возвращает ненулевое значение, если функция отработала удачно, или ноль - если отработала неудачно.
|
--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья
|