Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];

Вниз

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 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.015 c
14-1130912254
Holy
2005-11-02 09:17
2005.11.27
Измерение расстояния между компом и свитчом/компом.


14-1130968681
partizan
2005-11-03 00:58
2005.11.27
MAC адресс и IP


2-1131348915
axx
2005-11-07 10:35
2005.11.27
TThread


1-1130382539
skiph
2005-10-27 07:08
2005.11.27
Колонтитулы в Excel


1-1130936561
SergProger
2005-11-02 16:02
2005.11.27
Ошибка при закрытии





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский