скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Использование НООК в Delphi



Смотрит программер на монитор компа с только что поставленной виндой и говорит:
- Да.., жить захочешь не так раскорячишся.

Что такое НООК?

НООК - это механизм перехвата сообщений, предоставляемый системой 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.






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook