![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Опять Hook DLL :)
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 ?
Следует не тупо коприрвать пример а разобраться в этом прежде чем применят хуки.