Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Проблема с хуком

9.0K
22 мая 2007 года
ikro
31 / / 12.03.2007
Добрый день. Может быть кто-то сталкивался уже с такой проблемой...

На Delphi пишу библиотеку, содержащую процедуры установки глобального хука WH_CBT и саму процедуру хука. Этот хук должен просто вести статистику нажатия кнопок мыши, клавы и переключения окон и записывать это в файл. Все работает более-менее хорошо, пока не начну закрывать приложение - хук не освобождается. (Забавный эффект - когда закрываю приложение через Диспетчер Задач, вместе с приложением вываливается и Explorer :) ). Я пытался реализовать это дело двумя способами:
1. Все процедуры работы с файлом статистики записать непосредственно в библиотеку, где находится хук. Но эти файлы не закрываются по требованию приложения, потому что не освобождается хук. И такая ситуация меня не устраивает. Если бы только как-нибудь научить хук освобождаться по первому требованию...
2. Процедуры работы с файлом находятся в приложении, а хук при возникновении событий посылает сообщение главному окну программы, которая все и записывает. НО почему-то при таком подходе хук не работает, то есть ничего не отлавливает!!! Кроме переноса процедур работы с файлом ничего не изменял...

Подскажите пожалуйста, в чем могут быть проблемы/ошибки у этих способов?
И еще вопрос... Во всех статьях установка хука выглядит примерно следующим образом:
 
Код:
hook := SetWindowsHookEx(WH_CBT, @CbtProc, HInstance, 0);

НО при таком подходе хук отлавливает только события текущего приложения. Если же записать так:
 
Код:
hook := SetWindowsHookEx(WH_CBT, CbtProc, HInstance, 0);

то работает правильно. Так что, получается во всех статьях ошибки?! Или я что-то делаю неправильно?

Заранее спасибо за ответы...
18K
22 мая 2007 года
un_named
60 / / 24.04.2007
Хук освобождается функцией UnhookWindowsHookEx, впиши её в процедуру, которая освобождает хук, или обрабатывай по сообщению Виндовс WM_CLOSE. В качестве параметра этой функции передаётся хэндл, который выдаёт функция SetWindowsHookEx.
Кроме того, товарищ Iczelion советует использовать WH_CBN, а не WH_CBT хотя возможно это опечатка, хотя... http://www.netcode.ru/cpp/?artID=3116
Кстати, хоть я почти и не знаком с делфи, но правильнее кажется передавать процедуру с собачкой http://www.webstyleservice.ru/print.php?type=A&item_id=52
5.3K
23 мая 2007 года
Somebody
185 / / 24.12.2006
Цитата: ikro

И еще вопрос... Во всех статьях установка хука выглядит примерно следующим образом:
 
Код:
hook := SetWindowsHookEx(WH_CBT, @CbtProc, HInstance, 0);

НО при таком подходе хук отлавливает только события текущего приложения. Если же записать так:
 
Код:
hook := SetWindowsHookEx(WH_CBT, CbtProc, HInstance, 0);

то работает правильно. Так что, получается во всех статьях ошибки?! Или я что-то делаю неправильно?



Если CbtProc - это функция (а не переменная типа функция), то корректен первый вариант, а если это переменная типа TFnHookProc,- то второй вариант.

9.0K
23 мая 2007 года
ikro
31 / / 12.03.2007
По поводу способа передачи функции - это, конечно, палка о двух концах. На самом деле CbtProc - это процедура, но работает и тот и другой способ.
С установкой вроде я разобрался - сделал как написано в статье на исходниках.ru. Но возникла другая проблема, причем по-крупнее!
Ниже привожу код, а затем суть проблемы.
Код:
library ChHook;

uses
  Windows,
  Messages,
  SysUtils,
  UChConsts in '..\Server\UChConsts.pas',
  UChLog in 'Misc\UChLog.pas';

var
  MMFHandle: THandle;
  WMMyPost: Cardinal;


function CbtFunc(
  Code: Integer; WParam: WPARAM; LParam: LPARAM): LongInt; stdcall;
begin
  if Code < 0 then begin
    Result := CallNextHookEx(GlobalData^.SysHook, Code, WParam, LParam);
    Exit;
  end;

  case Code of
    HCBT_KEYSKIPPED:
      PostMessage(GlobalData^.AppWnd, WMMyPost, 2, 0);

    HCBT_CLICKSKIPPED:
      if
        (WParam = WM_LBUTTONDOWN) or (WParam = WM_RBUTTONDOWN) or
        (WParam = WM_MBUTTONUP)
      then
        PostMessage(GlobalData^.AppWnd, WMMyPost, 3, 0)
      else if WParam = WM_MOUSEWHEEL then
        PostMessage(GlobalData^.AppWnd, WMMyPost, 6, 0);

    HCBT_ACTIVATE:
      if GetParent(WParam) = 0 then
        PostMessage(GlobalData^.AppWnd, WMMyPost, 4, WParam);
  end;
  Result := CallNextHookEx(GlobalData^.SysHook, Code, WParam, LParam);
end;


procedure ManageHook(ASet: boolean; AWnd: HWND); export; stdcall;
begin
  if ASet then begin
    GlobalData^.SysHook := SetWindowsHookEx(WH_CBT, @CbtFunc, HInstance, 0);
    GlobalData^.AppWnd := AWnd;
    GlobalData^.WndMsg := RegisterWindowMessage('WM_MYPOST');

    if (GlobalData^.SysHook = 0) then
      DoLog('Hook: Unable to initialize hook');
  end
  else begin
    UnhookWindowsHookEx(GlobalData^.SysHook);
    GlobalData^.SysHook := 0;
  end;
end;


procedure OpenGlobalData;
begin
  MMFHandle :=
    CreateFileMapping(
      INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0,
      SizeOf(TGlobalDLLData), MMF_NAME);

  if (MMFHandle = 0) then
    Exit;

  GlobalData :=
    MapViewOfFile(
      MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
  if (GlobalData = nil) then begin
    CloseHandle(MMFHandle);
    Exit;
  end;
end;


procedure CloseGlobalData;
begin
  UnmapViewOfFile(GlobalData);
  CloseHandle(MMFHandle);
end;


procedure DLLEntryPoint(dwReason: DWORD); stdcall;
begin
  case dwReason of
    DLL_PROCESS_ATTACH: OpenGlobalData;
    DLL_PROCESS_DETACH: CloseGlobalData;
  end;
end;


{$R *.res}

exports
  ManageHook;

begin
  DLLProc:= @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.

А проблема вот какая. В ходе работы вылетают некоторые приложения - в частности Explorer. А выглядит это так: сначала появляется ошибка Access violation в explorer.exe, а следом за ним EAccessViolation в хуке. Где именно это происходит - никак отловить не могу. Одна из ситуаций, когда это стабильно происходит - это свертывании окон сочетанием <Windows>+D. Три часа сегодня бился над этой ошибкой - так и не поборол. В чем может быть проблема?

P.S. Ответы на вопросы "зачем CreateFileMapping" и т.д. находятся в статье, про которую я упомянул в начале...
9.0K
31 мая 2007 года
ikro
31 / / 12.03.2007
Все, вроде поборол. Жалко только, что новый вариант будет только под Windows 2000/XP работать :(
261
31 мая 2007 года
ahilles
1.5K / / 03.11.2005
а больше и не надо, или тебе Vista нужна? скоро выйдет delphi 2007 с поддержкой висты, если не ошибаюсь......
9.0K
05 июня 2007 года
ikro
31 / / 12.03.2007
Цитата: ahilles
а больше и не надо, или тебе Vista нужна? скоро выйдет delphi 2007 с поддержкой висты, если не ошибаюсь......


1. Не, мне не для Vistы хотелось бы, а для 98/ME.
2. Какая разница - Delphi 7 или 2007? Хуки пишутся средствами WinAPI, а не VCL, так что разницы в версии Delphi никакой ;) !

8.9K
06 июня 2007 года
Kap
77 / / 10.09.2006
В висте поменяли некоторые АПИ. Так что, это как повезет. Может и заработает =).
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог