Компонент Hotkey
Компонент Hotkey
Компонент Hotkey hook - это механизм перехвата сообщений, путем установки специальной функции на верх стека hook-функций системы. Без установки таких ловушек практически невозможно обойтись при написании различных средств удаленного администрирования, шпионов и других программ в той или иной степени осуществляющих контроль за пользователем, использующем ОС windows. hook'и бывают глобальные (на всю систему) и локальные (на какой-либо поток). Установить в систему hook можно при помощи функции setwindowshookex(), со следующим заголовком: hhook setwindowshookex(int idhook, hookproc lpfn, hinstance hmod, dword dwthreadid); Если ты плохо воспринимаешь Си-шный код, на delphi заголовок выглядит так: setwindowshookex(idhook: integer; lpfn: tfnhookproc; hmod: hinst; dwthreadid: dword): hhook; Функция setwindowshookex() в случае установки hook'a возвращает его дескриптор, в случае ошибки возвращает 0. Разберем подробней все входящие параметры этой функции: 1. idhook - константа, определяет типа устанавливаемого hook'а. Может принимать одно из ниже перечисленных значений: wh_callwndproc - Следит за сообщениями до отправки в оконную функцию и вызывается, когда процедуре окна посылается сообщение. Ловушка срабатывает при каждом вызове функции sendmessage. wh_callwndprocret - Контролирует сообщения после их отправки в оконную функцию. wh_cbt - Вызывается перед обработкой большинства сообщений окон, мыши и клавиатуры (созданием окон, активация окон, уничтожением окон, сменой размера окон, перед установкой фокуса и.т.п.) wh_debug - Вызывается перед любой другой ловушкой. Полезно для отладки hook'ов. wh_getmessage - Вызывается, когда из очереди приложения считывается сообщение. wh_hardware - Вызывается, когда из очереди приложения считывается сообщение установленного на компьютере оборудования. wh_journalplayback - Вызывается, когда из очереди системы считывается сообщение. Применяется для добавления в очередь системных событий. wh_journalrecord - Вызывается, когда из очереди системы запрашивается какое-нибудь событие. Применяется для регистрации системных событий. wh_keyboard - Вызывается, когда из очереди приложения считывается сообщения wm_keydown или wm_keyup. Одна из самых распространенных ловушек -). wh_mouse - Вызывается, когда из очереди приложения считывается сообщение мыши. wh_msgfilter - Вызывается, когда сообщение должно быть обработано диалоговым окном приложения, меню или окном приложения. wh_shell - Вызывается, когда создаются и разрушаются окна верхнего уровня или когда приложению-оболочке требуется стать активным. 2. lpfn - указатель на саму hook функцию. Ее заголовок: function hookfunction(code: integer; wparam: wparam; lparam: lparam): lresult stdcall; Значения входящих параметров зависят от типа hook'a. Если ставится глобальный hook, эта функция должна обязательно находиться в dll. 3. hmod - принимает значение hinstance или дескриптор dll (в глобальных ловушках). 4. dwthreadid - идентифицирует поток, в который вставляется ловушка. В глобальных hook'ах этот параметр должен быть равен 0. Для удаления установленной ловушки существует функция unhookwindowshookex(). В качестве параметра нужно использовать указатель (дескриптор) на hook функцию (значение, которое возвращает функция setwindowshookex()). Ну вот и все, с основами мы ознакомлены. Теперь напишем маленькую шуточную программу, ставящую hook на считывания сообщений мыши (wh_mouse). Сделаем так, чтобы при нажатии на правую кнопку мыши скрывалась кнопка "Пуск", при нажатии на левую - появлялась, среднею - изменялся заголовок активного окна. Сама hook функция будет находиться в dll. Кроме того, в dll будут находиться две процедуры - sethook() и removehook(), соответственно устанавливающие и удаляющие ловушку. Привожу код dll библиотеки: library lib; uses windows,messages; var h : thandle; {hook-функция} function hook(c0de, wparam, lparam : integer): lresult; stdcall; {Объявления переменных} var w : thandle; hw : hwnd; begin {Если c0de не меньше 0, все в порядке, продолжаем} if c0de >= 0 then begin { Если wparam = wm_rbuttonup, т.е. нажата правая кнопка мыши, получаем хендл (handle) кнопки "Пуск" и скрываем ее } case wparam of wm_rbuttonup : begin w:= findwindow('shell_traywnd', nil); w:= findwindowex(w, hwnd(0),'button', nil); showwindow(w, sw_hide); end; { Если wparam = wm_lbuttonup, т.е. нажата левая кнопка мыши, получаем хендл кнопки пуск и показываем ее } wm_lbuttonup: begin w:= findwindow('shell_traywnd', nil); w:= findwindowex(w, hwnd(0),'button', nil); showwindow(w, sw_show); end; { Если wparam = wm_mbuttonup, т.е. нажата средняя кнопка мыши, получаем указатель на заголовок активного окна и изменяем его } wm_mbuttonup: begin hw:=getforegroundwindow; setwindowtext(hw,'example of windows hook (wh_mouse) - by dark lord '); end; end; end else {Если c0de меньше 0} begin {Вызываем следующую ловушку в цепочке ловушек windows и выходим из процедуры} result := callnexthookex(h, c0de, wparam, lparam); exit; end; {Вызываем следующую ловушку в цепочке ловушек windows} result := callnexthookex(h, c0de, wparam, lparam); end; { Процедура установки ловушки, если не удалось установить - выводим сообщение об ошибке } procedure sethook; begin h:= setwindowshookex(wh_mouse, @hook, hinstance, 0); if h = 0 then messagebox(0,'hmmm..','error',mb_iconhand); end; { Процедура удаления ловушки } procedure removehook; begin unhookwindowshookex(h); end; { Экспорт процедур установки и удаления hook'a } exports sethook index 1 name 'sethook', removehook index 2 name 'removehook'; end. В самой программе ловушка будет устанавливаться вызовом из dll процедуры sethook, удаляться - вызовом процедуры removehook. В данной статье были рассмотрены только основы установки ловушек. Есть немалое количество нюансов и возникающих проблем при установке нескольких hook'ов, установки hook'ов в разных ОС (особенно это касается глобальных ловушек). Для получения подробностей по этим вопросам рекомендую использовать win32 api reference или msdn (если нет диска с msdn - прогуляйтесь на http://msdn.microsoft.com, здесь правда не вся информация, но большая ее часть).