Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Опять Hook DLL :)


Страницы:   1 2

Goorus ©   (2005-02-12 12:50:00) 

Пишу компонент, для перехвата событий клавиатуры и мыши. Хотел избавиться от SendMessage при получении сообщения, но ничего не получилось :(
Если вызывать RunHook, то сообщения перехватываются до тех пор, пока приложение активно, если оно теряет фокус, то AppProcKeybrd больше не вызывается, даже если фокус вернуть.
В прнципе, выриант RunHook2 работает нормально, но просто не хотелось бы лишний раз отсылать сообщение.

Вот код библиотеки:

library HookLibrary;

uses
 Windows, Messages;

const
 MMFName = 'g_HookMs';

type

 TObjHookProc = procedure(WParam: WParam; LParam: LParam)of object;

 TGlobalData = record
   shKeybrd: HWnd;  // дескриптор ловушки клавы
   shMouse : HWnd;  // ловушки мыши

   shKeybrd2: HWnd;

   AppWnd: HWnd;
 end;
 PGlobalData = ^TGlobalData;

var
 AppProcKeybrd: TObjHookProc;
 AppProcMouse : TObjHookProc;

 InWorking: Boolean = False;
 Runing: Boolean = False;

 MMFHandle: THandle;

 GlobalData: PGlobalData;

function SysMsgKeybrdProc(code: Integer; WParam: WParam; LParam: LParam): LResult; stdcall;
begin
 with GlobalData^ do
 if (code = HC_ACTION) and (not InWorking) then
 try
   InWorking := True;
   AppProcKeybrd(WParam, LParam);
 finally
   Result := CallNextHookEx(shKeybrd, Code, wParam, LParam);
   InWorking := False;
 end
 else
   Result := CallNextHookEx(shKeybrd, Code, wParam, LParam);
end;

function SysMsgKeybrdProc2(code: Integer; WParam: WParam; LParam: LParam): LResult; stdcall;
begin
 with GlobalData^ do
 if (code = HC_ACTION) and (not InWorking) then
 try
   InWorking := True;
   SendMessage(AppWnd, WH_KEYBOARD, wParam, LParam);
 finally
   Result := CallNextHookEx(shKeybrd2, Code, wParam, LParam);
   InWorking := False;
 end
 else
   Result := CallNextHookEx(shKeybrd2, Code, wParam, LParam);
end;

function SysMsgMouseProc(code: Integer; WParam: WParam; LParam: LParam): LResult; stdcall;
begin
 with GlobalData^ do
 if (code = HC_ACTION) and (not InWorking) then
 try
   InWorking := True;
   AppProcMouse(WParam, LParam);
 finally
   Result := CallNextHookEx(shMouse, Code, wParam, LParam);
   InWorking := False;
 end
 else
   Result := CallNextHookEx(shMouse, Code, wParam, LParam);
end;

function RunHook(OnKeybrd, OnMouse: TObjHookProc): Boolean; export; stdcall;
begin
 Result := False;
 with GlobalData^ do
 if not Runing then
 try
   AppProcKeybrd := OnKeybrd;
   AppProcMouse := OnMouse;
   if not(Assigned(OnKeybrd) or Assigned(OnMouse)) then Exit;

   if Assigned(OnKeybrd) then
     shKeybrd := SetWindowsHookEx(WH_KEYBOARD, @SysMsgKeybrdProc, hInstance, 0);

   if Assigned(OnMouse) then
     shMouse := SetWindowsHookEx(WH_MOUSE, @SysMsgMouseProc, hInstance, 0);

   Result := True;
   Runing := True;
 except

 end;
end;

function RunHook2(OnKeybrd: HWnd): Boolean; export; stdcall;
begin
 Result := False;
 with GlobalData^ do
 if not Runing then
 try
   AppWnd := OnKeybrd;

   shKeybrd2 := SetWindowsHookEx(WH_KEYBOARD, @SysMsgKeybrdProc2, hInstance, 0);

   Result := True;
   Runing := True;
 except

 end;
end;

procedure StopHook(); export; stdcall;
begin
 with GlobalData^ do
 try
   UnHookWindowsHookEx(shKeybrd);
   UnHookWindowsHookEx(shMouse);
   UnHookWindowsHookEx(shKeybrd2);
 finally
   shKeybrd := 0;
   shMouse := 0;
   shKeybrd2 := 0;
 end;
 Runing := False;
end;

procedure OpenGlobalData;
begin
 // получаем объект файлового отображения
 MMFHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE,
   0, SizeOf(TGlobalData), MMFName
 );
 if MMFHandle = 0 then
 begin
   MessageBox(0, 'Невозможно создать FileMapping', 'Сообщение из HookLib.dll', 0);
   Exit;
 end;
 // отображаем глобальные данные на АП вызывающего процесса и
 // получаем указатель на начало выделенного пространства
 GlobalData := MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0,
   SizeOf(TGlobalData)
 );
 if GlobalData = nil then
 begin
   CloseHandle(MMFHandle);
   MessageBox(0, 'Невозможно создать MapViewOfFile', 'Сообщение из HookLib.dll', 0);
   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: begin
     if Runing then StopHook;
     CloseGlobalData;
   end;
 end;
end;

exports RunHook;
exports RunHook2;
exports StopHook;

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


GuAV   (2005-02-12 20:15:00) [21]


> На счёт трюка с GlobalData, опыты показали, что
>shKeybrd
> (shMouse, shKeybrd2) должны находиться именно там,
> иначе не работает.


Жаль. Следует всё же понять почему shKeybrd, shMouse, shKeybrd2 должны быть именно там. Здесь лежит одна из причин

> почему он перестаёт быть валидным когда приложение
> перестаёт быть активным


Другая причина - здесь.

> DLL начинает пытаться вызвать эти методы у него?



> Ведь DLL подключена к моему приложению.

Нет. Точнее не только.


> Работает - не трогай! Золотое правило :)

Жаль. А я хотел помочь...


> Это не имеет значения, у меня свой обработчик.

Ну и что. Выпенреж может стоить геморроя.

Читай
http://www.delphimaster.ru/articles/hooks/index.html


Piter   (2005-02-12 18:03:00) [22]

Goorus ©   (12.02.05 18:00) [2]
> А почему не safecall ?
Работает - не трогай!


а-а-а-а... я сейчас сползу со стула...


Goorus   (2005-02-12 18:00:00) [23]

> А почему не safecall ?
Работает - не трогай! Золотое правило :)

На счёт трюка с GlobalData, опыты показали, что shKeybrd
(shMouse, shKeybrd2) должны находиться именно там, иначе не работает.

> WH_KEYBOARD = WM_DESTROY
Это не имеет значения, у меня свой обработчик.

Про метод я понимаю, только не понимаю, почему он перестаёт быть валидным когда приложение перестаёт быть активным. Ведь DLL подключена к моему приложению.
Или, когда фокус получает другое приложения, DLL начинает пытаться вызвать эти методы у него? Сам не верю в то, что сказал :)


GuAV   (2005-02-12 15:38:00) [24]


>   SendMessage(AppWnd, WH_KEYBOARD, wParam, LParam);

WH_KEYBOARD = WM_DESTROY. очень интересное совпадение.
см. справку по WM_USER


> procedure DLLEntryPoint(dwReason: DWord); stdcall;


А почему не safecall ?


>   AppProcKeybrd := OnKeybrd;
>    AppProcMouse := OnMouse;


Ну во первых метод по сути пара указателей - на код и на экземпляр объекта. Угадай, какой из них будет валидным в чужом АП.

И кстати зачем этот трюк с GlobalData ?

Следует не тупо коприрвать пример а разобраться в этом прежде чем применят хуки.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо