Использование HOOK в Дельфи

=== Использование HOOK в Дельфи ===
; Что такое НООК?
: НООК - это механизм перехвата сообщений, предоставляемый системой Microsoft Windows. Программист пишет специального вида функцию (НООК-функция), которая затем при помощи функции SetWindowsHookEx вставляется на верх стека НООК-функций системы. Ваша НООК-функция сама решает, передать ли ей сообщение в следующую НООК-функцию при помощи CallNextHookEx или нет.
; Какие бывает НООК'и?
: НООК бывают глобальные, контролирующие всю систему, так и локальные, ориентированные на какой-либо поток (Thread). Кроме того НООК различаются по типу перехватываемых сообщений (подробнее об этом - ниже). НООК несколько подтормаживают систему, поэтому ставить их рекомендуется только при необходимости, и кактолько необходимость в них отпадает - удалять.
; Как создавать НООК?
: НООК устанавливается в систему при помощи функции SetWindowsHookEx, вот её заголовок:
 function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK;
* idHook - константа, определяющая тип вставляемого НООК'а, должна быть одна из нижеследующих констант:
** WH_CALLWNDPROC - вставляемая НООК-функция следит за всеми сообщения перед их отпралением в соответствующую оконную функцию
** WH_CALLWNDPROCRET - вставляемая НООК-функция следит за всеми сообщениями после их отправления в оконную функцию
** WH_CBT - вставляемая НООК-функция следит за окнами, а именно: за созданием, активацией, уничтожением, сменой размера; перед завершением системной команды меню, перед извлечением события мыши или клавиатуры из очереди сообщений, перед установкой фокуса и т.д.
** WH_DEBUG - вставляемая НООК-функция следит за другими НООК-функциями.
** WH_GETMESSAGE - вставляемая НООК-функция следит за сообщениями, посылаемыми в очередь сообщений.
** WH_JOURNALPLAYBACK - вставляемая НООК-функция посылает сообщения, записанные до этого WH_JOURNALRECORD НООК'ом.
** WH_JOURNALRECORD - эта НООК-функция записывает все сообщения куда-либо в специальном формате, причем позже они могут быть "воспроизведены" при помощи НООК'а WH_JOURNALPLAYBACK. Это в некотором роде аналог магнитофонной записи сообщений.
** WH_KEYBOARD - вставляемая НООК-функция следит за сообщениями клавиатуры
** WH_MOUSE - вставляемая НООК-функция следит за сообщениями мыши
** WH_MSGFILTER
** WH_SHELL
** WH_SYSMSGFILTER
* lpfn - указатель на непосредственно функцию. Обратите внимание, что если Вы ставите глобальный НООК, то НООК-функция обязательно должна находиться в некоторой DLL!!!
* hmod - описатель DLL, в которой находится код функции.
* dwThreadId - идентификатор потока, в который вставляется НООК
Подробнее о НООК-функциях смотри справку по Win32API.
; Как удалять НООК?
: НООК удаляется при помощи функции UnHookWindowsEx.
; Пример использования НООК.
: Ставим НООК, следящий за мышью (WH_MOUSE). Программа следит за нажатием средней кнопки мыши, и когда она нажимается, делает окно, находящееся непосредственно под указателем, поверх всех остальных (TopMost). Код самой НООК-функции помещен в библиотеку lib2.dll, туда же помещены и функции Start - для установки НООК, и Remove - для удаления НООК.
==== Файл sticker.dpr ====
program sticker;
uses
 Windows,
 Messages;
var
 wc: TWndClassEx;
 MainWnd: THandle;
 Mesg: TMsg;
 // экспортируем две функции из библиотеки с НООК'ами
 procedure Start; external 'lib2.dll' Name 'Start';
 procedure Remove; external 'lib2.dll' Name 'Remove';
 function WindowProc(wnd: HWND; Msg: Integer; wParam: WParam;
 lParam: LParam): LResult; stdcall;
 var
 nCode, ctrlID: Word;
 begin
 case msg of
 wm_destroy:
 begin
 Remove; // удаляем НООК
 PostQuitMessage(0);
 exit;
 Result := 0;
 end;
 else
 Result := DefWindowProc(wnd, msg, wParam, lParam);
 end;
 end;
begin
 wc.cbSize := SizeOf(wc);
 wc.style := cs_hredraw or cs_vredraw;
 wc.lpfnWndProc := @WindowProc;
 wc.cbClsExtra := 0;
 wc.cbWndExtra := 0;
 wc.hInstance := HInstance;
 wc.hIcon := LoadIcon(0, idi_application);
 wc.hCursor := LoadCursor(0, idc_arrow);
 wc.hbrBackground := COLOR_BTNFACE + 1;
 wc.lpszMenuName := nil;
 wc.lpszClassName := 'WndClass1';
 RegisterClassEx(wc);
 MainWnd := CreateWindowEx(0, 'WndClass1', 'Caption', ws_overlappedwindow,
 cw_usedefault, cw_usedefault, cw_usedefault, cw_usedefault, 0, 0,
 Hinstance, nil);
 ShowWindow(MainWnd, CmdShow);
 Start; // вставляем НООК
 while GetMessage(Mesg, 0, 0, 0) do
 begin
 TranslateMessage(Mesg);
 DispatchMessage(Mesg);
 end;
end.
==== Файл lib2.dpr ====
library lib2;
uses
 Windows,
 Messages;
var
 pt: TPoint;
 theHook: THandle;
function MouseHook(nCode, wParam, lParam: Integer): LResult; stdcall;
var
 msg: PMouseHookStruct;
 w: THandle;
 style: Integer;
begin
 if nCode < 0 then
 begin
 Result := CallNextHookEx(theHook, nCode, wParam, lParam);
 Exit;
 end;
 msg := PMouseHookStruct(lParam);
 case wParam of
 WM_MBUTTONDOWN:
 pt := msg^.pt;
 WM_MBUTTONUP:
 begin
 w := WindowFromPoint(pt);
 style := GetWindowLong(w, GWL_EXSTYLE);
 if (style and WS_EX_TOPMOST) <> 0 then
 begin // уже поверх всех - сделать обычным
 ShowWindow(w, sw_hide);
 SetWindowPos(w, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW);
 end
 else
 begin // сделать поверх остальных
 ShowWindow(w, sw_hide);
 SetWindowPos(w, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW);
 end;
 end;
 end;
 Result := CallNextHookEx(theHook, nCode, wParam, lParam);
end;
procedure Start;
begin
 theHook := SetWindowsHookEx(wh_mouse, @mouseHook, hInstance, 0);
 if theHook = 0 then
 MessageBox(0, 'Error!', 'Error!', mb_ok);
end;
procedure Remove;
begin
 UnhookWindowsHookEx(theHook);
end;
exports
 Start index 1 Name 'Start',
 Remove index 2 Name 'Remove';
end.
Всё.
 (С) Автор статьи: Sergey Stolyarov
 Development и Дельфи (http://MDelphi.far.ru).
Author: StayAtHome
Source: Взято с Vingrad.ru http://forum.vingrad.ru
ID: 02220