Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.11.27;
Скачать: CL | DM;

Вниз

SetWindowsHookEx и невнимательность ?   Найти похожие ветки 

 
Sphinx ©   (2005-09-20 21:15) [0]

Есть код установки хука и снятия
//------------------------------------------------------------------------------
// функция установки ловушки
//------------------------------------------------------------------------------

function SetWndProcHook: HResult; stdcall;
begin
 WndProcHook := SetWindowsHookEx(WH_CALLWNDPROC {WH_KEYBOARD}, @HookWindowProc, HInstance, 0);
 if WndProcHook = 0 then
   SetWndProcHook := E_FAIL
 else
   SetWndProcHook := S_OK;
end;

//------------------------------------------------------------------------------
// функция снятия ловушки
//------------------------------------------------------------------------------

function UnSetWndProcHook: HResult; stdcall;
begin
 if UnhookWindowsHookEx(WndProcHook) then
   UnSetWndProcHook := S_OK
 else
   UnSetWndProcHook := E_FAIL;
end;


Есть callback функция
//------------------------------------------------------------------------------
// функция обработки сообщений ловушки
//------------------------------------------------------------------------------

function HookWindowProc(nCode: Longint; wParam, lParam: Longint): Longint; stdcall;
var
 pMsgStruct : PCWPStruct;
begin
 HookWindowProc := CallNextHookEx(WndProcHook, nCode, wParam, lParam);
end;


вот так все работает без проблем.
Но стоит только повесить какую-либо обработку в функцию, например:
//------------------------------------------------------------------------------
// функция обработки сообщений ловушки
//------------------------------------------------------------------------------

function HookWindowProc(nCode: Longint; wParam, lParam: Longint): Longint; stdcall;
var
 pMsgStruct : PCWPStruct;
begin
 HookWindowProc := CallNextHookEx(WndProcHook, nCode, wParam, lParam);
 if nCode = HC_ACTION then
   begin
     pMsgStruct := Pointer(lParam);
     if pMsgStruct^.hwnd = AppWindowHandle then
       begin
         case pMsgStruct^.message of
           WM_KEYDOWN  : begin
//                            MessageBox(0, "KeyDown", "Debug", mb_ok);
                         end;
         end;
       end;
   end;
end;

и система падает. (выскакивают AV explorer.exe и всех остальных процессов с обращением к нулевой памяти)

Если выставить ловушку только на клавиатуру - то таких проблем нет, все корректно обрабатывается.

Хук естественно выполняется в dll. Такое ощущение, что какую-то мелочь пропустил по невнимательности (с хуками работаю в первый раз).

Суть задачи - следить за клавиатурой и мушью в пределах одного окна (ставить хук на клаву и мышь отдельно не хочется, потому, что не понял как в таком случае отлавливать события нажатия кнопки мыши).


 
ANB ©   (2005-09-20 21:48) [1]


> MessageBox(0, "KeyDown", "Debug", mb_ok);
- вот это ты зря. Совсем зря. Нет фильтра на сообщения (реагируешь на движения мыши даже в своем приложении).


> AppWindowHandle
- откуда берешь это значение ?

Короче, вот рабочая хуковая DLL. Приладь там, что тебе нужно.

library Recorder;

uses Windows, Messages, SysUtils;

const
 MMFName : PChar = "Recorder_MMF"; // имя объекта файлового отображения

{структура, поля которой будут отображены в файл подкачки}
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
 SysHook : HWND; // дескриптор установленной ловушки
 MainRecorderWnd : hWnd; // дескриптор окна рекордера
 MainRecorderProcessID : THandle; // ID процесса рекордера
end;

var
MMFHandle :        THandle;
WM_Recorder_HOOK : Cardinal;
GlobalData :       PGlobalDLLData;

function RecordCallBackProc(Code : Integer;
                           wParam : WPARAM;
                           lParam : LPARAM) : LRESULT; stdcall;
var hCallWnd : HWND;
   ProcessID : THandle;
   EventMsg : TMsg;
   SysHook : THandle;
   MsgData : TCOPYDATASTRUCT;
begin
Result := 0;
SysHook := 0;
try
 // Прочитаем SysHook из разделяемой памяти
 SysHook := GlobalData^.SysHook;
 // Проверим коды
 if (Code <> HC_ACTION) then Exit;
 if (wParam <> PM_REMOVE) then Exit;
 EventMsg := TMsg(Pointer(lParam)^);
 hCallWnd := EventMsg.hwnd;

 // Выкинем лишние сообщения
 if (
    (EventMsg.message = WM_KEYDOWN)
 or (EventMsg.message = WM_SYSKEYDOWN)
 or (EventMsg.message = WM_COMMAND)
 or (EventMsg.message = WM_LBUTTONDOWN)
 or (EventMsg.message = WM_RBUTTONUP)
 or (EventMsg.message = WM_MBUTTONUP)
 ) then begin
  // Проверим, что события не нашего приложения
  GetWindowThreadProcessId(hCallWnd, ProcessID);
  if (ProcessID = GlobalData^.MainRecorderProcessID) then Exit;
  // Передадим инфу о событии в рекордер
  MsgData.dwData := WM_Recorder_HOOK;
  MsgData.cbData := SizeOf(EventMsg);
  MsgData.lpData := @EventMsg;
  SendMessage(
   GlobalData^.MainRecorderWnd
  ,WM_COPYDATA
  ,hCallWnd
  ,Integer(@MsgData));
 end;
finally
 CallNextHookEx(SysHook, Code, wParam, lParam);
end;
end;

{Процедура установки HOOK-а}
function Set_Hook(hMainWnd : HWND; MainProcessID : THandle) : Boolean; export; stdcall;
begin
// Устанавливаю HOOK
Result := False;
// Поставим хук
GlobalData^.SysHook := SetWindowsHookEx(WH_GETMESSAGE, @RecordCallBackProc,
                                        HInstance, 0);
GlobalData^.MainRecorderWnd := hMainWnd;
GlobalData^.MainRecorderProcessID := MainProcessID;
if (GlobalData^.SysHook = 0)
then
 MessageBox(0, "Ошибка : не удалось установить хук WH_GETMESSAGE !",
            "Сообщение от Recorder.dll", 0)
else Result := True;
end;

{Процедура снятия HOOK-а}
function Reset_Hook() : Boolean; export; stdcall;
begin
// Удаляем функцию-фильтр
Result := False;
// Снимем хук
if (not UnhookWindowsHookEx(GlobalData^.SysHook))
then MessageBox(0, "Ошибка : не удалось снять хук WH_GETMESSAGE !",
                "Сообщение от Recorder.dll", 0)
else Result := True;
end;

procedure OpenGlobalData();
var sMsg : String;
begin
// Зарегистрим наше сообщение
WM_Recorder_HOOK := RegisterWindowMessage("WM_Recorder_HOOK");
// Подключим MMF
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0,
                              SizeOf(TGlobalDLLData), MMFName);
if MMFHandle = 0 then begin
 sMsg := "Ошибка : не удалось создать MMF <" + MMFName + ">";
 MessageBox(0, PChar(sMsg), "Сообщение от Recorder.dll", 0);
 Exit;
end;
GlobalData := MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0,
                            SizeOf(TGlobalDLLData));
if (GlobalData = nil) then begin
 sMsg := "Ошибка : не удалось отобразить MMF <" + MMFName + ">";
 MessageBox(0, PChar(sMsg), "Сообщение от Recorder.dll", 0);
end;
end;

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

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

exports Set_Hook, Reset_Hook;

begin
{назначим поцедуру переменной DLLProc}
DLLProc := @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
 библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.


 
Sphinx ©   (2005-09-20 22:06) [2]

2 ANB ©
Рад бы не реагировать - но я просто проверял этим работоспособность кода...
А мне в ответ систему валило :(

> > AppWindowHandle
> - откуда берешь это значение ?

при инициализации dll вводится THandle окна, события которого и надо отслеживать (кроме отслеживание событий библиотека еще некоторые функции с окном выполняет).
Собственно этот хэндл и хранится в AppWindowHandle

Эту (или подобную dll я уже скачал из соответствующей статьи тут), но тогда придется многое у себя переделать, если в моем коде ошибка в самой задаче установки хука - тогда ни куда уж не денешься, а если я всего-лишь что-то пропустил, то может можно просто исправить, не меняя сильно структуру библиотеки.


 
ANB ©   (2005-09-20 22:17) [3]


> Собственно этот хэндл и хранится в AppWindowHandle
- а в копиях - теряется. Внедряется только код, все переменные становятся неопределенными. Думаешь мне очень хотелось MMF использовать ?


 
Sphinx ©   (2005-09-20 22:26) [4]

2 ANB ©
Тааааак...кажется дошло...
Завтра проверю...
Но если это глобальная переменная для библиотеки, и в упрощенном виде:
procedure Init(iHandle: THandle);
begin
AppWindowHandle := iHandle
end;

Все равно значение будет потеряно ???


 
ANB ©   (2005-09-20 22:51) [5]

Есно. Почитай про процесс внедрения. Об этом даже в статье на этом сайте говорится. Там есть только одна ошибка в примере. А так - все грамотно разжевано. Я свой код из этого примера лепил.


 
Sphinx ©   (2005-09-21 09:47) [6]

Ладно, с этим еще поразбираюсь...
Настораживает следующее. Внимательно просмотрел пример и вот, что нашел:
function KeyboardProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
В то время как и в Windows SDK из Delphi7 и в MSDN January2005
LRESULT CALLBACK CallWndProc(
   int nCode,
   WPARAM wParam,
   LPARAM lParam
);


Windows.pas
WPARAM = LongInt;
у меня написано
function HookWindowProc(nCode: Longint; wParam, lParam: Longint): Longint; stdcall;
и собственно любая попытка получить данные приводит к падению системы...

Так каким должен быть второй параметр Word или Longint(WPARAM) ???


 
Sphinx ©   (2005-09-21 09:49) [7]

Сорри...для одинаковости привожу обратный вызов для клавиатуры:
LRESULT CALLBACK KeyboardProc(
   int code,
   WPARAM wParam,
   LPARAM lParam
);

все равно та же фигня с WPARAM


 
ANB ©   (2005-09-21 11:14) [8]


> word
- замени на DWord. А ты это в чьем примере нашел ? Неужто у меня ?
Возьми статью, а для примера возьми мою DLL. Если очень надо - могу выложить код ставящего хук и принимающего сообщения модуля. Но там много лишнего.


 
Sphinx ©   (2005-09-21 11:28) [9]

2 ANB ©
в примере к статье...
http://delphimaster.ru/articles/hooks/index.html

кстати об этом же написано и в
http://delphimaster.net/view/4-1121277980/ (9й пост)

интересно, что там именно Word а не DWord :\

сейчас нету под рукой Делфи...смогу проверить только вечером.
Огромное спасибо...если не получится - просто откопипастю какой-нибудь пример и подгоню под свои нужды...


 
ANB ©   (2005-09-21 14:53) [10]


> Sphinx ©   (21.09.05 11:28) [9]
- ну так и копипасти мой. Я для чего его выкладывал ?


 
-=S..S=-   (2005-09-27 11:14) [11]

У меня была аналогичная проблема ... ANB ©   (20.09.05 22:17) [3] абсолютно прав ... надо использовать глобал мемори ... иначе никак ... писал я как то длл которая и на клаву и на мышу реагировала ... все ок было .. токо хз когда я до неё доберусь :) ... если очень надо то в понедельник скорее всего скину ... да и впринципе тебе уже всё обяснили .. так что часика два посиди .. сам напишешь :)


 
Sphinx ©   (2005-09-27 14:53) [12]

Я уже сделал...
Огромное спасибо - все норм реагирует :)



Страницы: 1 вся ветка

Текущий архив: 2005.11.27;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.029 c
14-1131377741
DiamondShark
2005-11-07 18:35
2005.11.27
Net 2.0 и все-все-все


14-1131014094
QuasiLamo
2005-11-03 13:34
2005.11.27
Не хочу рекурсию


3-1129369145
AlexLines
2005-10-15 13:39
2005.11.27
Поиск в БД


4-1127564241
Реактор
2005-09-24 16:17
2005.11.27
Keybd_Event не хочет нажимать на "точку"


14-1131446476
Аноним
2005-11-08 13:41
2005.11.27
Аномальное явление?