Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Использование НООК в 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.

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay