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

Вниз

Передать хенда программы в DLL?   Найти похожие ветки 

 
NetKnight ©   (2003-10-10 02:22) [0]

Вообщем есть такая прога:


program winctrls;

uses
Messages, Windows, SysUtils;

var
Message:TMsg;
ProcAddr,MAP:Pointer;
DLL:HINST;
sPath:string;
Handle,MapHandle:THandle;

begin
sPath:=ExtractFilePath(ParamStr(0))+"keyhook.dll";
DLL:=LoadLibrary(PChar(sPath));
ProcAddr:=GetProcAddress(DLL,PChar("KeyboardProc"));
Handle:=GetCurrentProcess;
MapHandle:=CreateFileMapping($ffffffff,nil,PAGE_READWRITE, 0, 64000, PChar("AppHandle"));
MAP:=MapViewOfFile(MapHandle,FILE_MAP_WRITE,0,0,64000);
StrPCopy(MAP,PChar(@Handle));
FlushViewOfFile(Map,64000);
UnMapViewOfFile(Map);
SetWindowsHookEx(WH_KEYBOARD,ProcAddr,DLL,0);
While GetMessage (Message, 0, 0, 0) do
begin
TranslateMessage (Message);
DispatchMessage (Message);
end;
Halt(Message.wParam);
end.


И вот такая DLL c функцией обработки клавиатурных сообщений:

library keyhook;

uses
Messages, Windows, SysUtils;

{$R *.res}

function KeyboardProc(Code:integer;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
var msg:string;
MAP:Pointer;
MapHandle,AppHandle:THandle;
begin
MapHandle:=OpenFileMapping(FILE_MAP_READ, true, PChar("AppHandle"));
Map := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 64000);
AppHandle:=Cardinal(PChar(MAP));
msg:=inttostr(AppHandle);
Result:=0;
if (lParam<0) then
begin
if (lParam=KF_ALTDOWN) then MessageBox(0,PChar("ALT PRESSED"),PChar("ALT ALERT!"),0);
case wParam of
VK_SPACE:
begin
MessageBox(0,PChar(msg),PChar("HOOK ALERT!"),0);
end;
end;
end;
end;

exports
KeyboardProc;

begin
end.


Ясен пень, что программа не дописана, но суть я думаю ясна. Нужно перехватывать ВСЕ сообщения клавиатуры. Вроде как всё работает, но когда через FileMapping передаётся хендл, то он почему-то получается в ДЛЛ не такой, как отправляет его программа. Как можно передать хендл тут? Или можно ли это всё в одном файле сделать? у меня не получалось.. :(


 
Digitman ©   (2003-10-10 09:09) [1]

для начала вместо
StrPCopy(MAP,PChar(@Handle));
напиши
PInteger(MAP)^ := Handle

а вместо
AppHandle:=Cardinal(PChar(MAP));
напиши
AppHandle:=THandle(PInteger(MAP)^);

а вообще несуразиц в твоем коде немало

1. Каков смысл передавать в хук-ДЛЛ псевдохэндл процесса, устанавливающего хук ? Ну получил ты его, предположим ...Как ты собираешься его далее в теле хук-ДЛЛ использовать ?

2. Зачем всякий раз при исполнении тела процедуры KeyboardProc() создавать FileMap-объект ? Достаточно сделать это 1 раз в ходе инициализации хук-ДЛЛ


 
NetKnight ©   (2003-10-10 13:24) [2]

Вообщем смысл в том, что нужно по определённому сообщению клавиатуры завершить программу, а для этого нужен хендал, чтоб выполнить closehandle.
Или есть способы проще?


 
Digitman ©   (2003-10-10 14:29) [3]

с closehandle() брось затею.
не будет это работать в том примитивном виде, как ты себе представляешь

процесс, устанавливающий хук, может, например, создать объект синхронизации типа event.

после создания event"а устанавливается собственно хук и далее в цикле выполняется MsgWaitForMultipleObjects(), чтобы реагировать на оконные сообщения и одновременно ждать срабатывания eventa.

хук-DLL при инициализации получает хэндл event"а по заранее оговоренному его имени.

процедура KeyboardProc() при обнаружении нужного клав.сообщения "сигналит" event"ом, сигнал "ловится" приложением, это - условие выхода из цикла ожидания, следом за которым хук снимается и приложение можно завершать банальным Application.Terminate


 
NetKnight ©   (2003-10-10 16:24) [4]

Digitman
А может мьютекс создать и как он пропадает, рубить программу? :)

Кстати Application в консольном режиме не сущевствует. Она только в оконных прогах есть. Тут можно только убить процесс.
Или я в юниксах пересидел? :)


 
Ketmar   (2003-10-10 16:32) [5]

>NetKnight © (10.10.03 16:24) [4]
ты прав. нету. если не создать руками %-) но, тем не менее, можно создать поток, который будет получать сообщения (есть такая фича). и ждать сообщения WM_USER_I_MUST_DIE %-)


 
Digitman ©   (2003-10-10 16:33) [6]


> А может мьютекс создать


а какая разница ? мьютекс - тоже объект синхронизации


> Кстати Application в консольном режиме не сущевствует


потому что объект TApplication никто не создавал.
создай - будет существовать.


> Тут можно только убить процесс.


чушь.


 
nikkie ©   (2003-10-10 16:37) [7]

передавать надо не хендл, а id. и лучше не процесса, а потока. тогда можно будет отправлять сообщения через PostThreadMessage. а иначе не очень понятно зачем цикл выборки сообщений написан.


 
NetKnight ©   (2003-10-11 20:52) [8]

А можно поточнее объяенить, как это должно работать? Что-то не очень понятно..


 
nikkie ©   (2003-10-11 21:58) [9]

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

1. передавать не хендл, а id потока, получаемого с помощью
GetCurrentThreadId

2. прервать цикл выборки сообщений в программе можно, послав WM_QUIT:
PostThreadMessage(ThreadId, WM_QUIT, 0, 0)

3. поскольку в программе никаких окон не создается, то смысла в TranslateMessage/DispatchMessage нет. вреда, впрочем, тоже.

4. ну и учти то, что тебе Digitman написал про передачу данных и FileMapping.


 
NetKnight ©   (2003-10-13 15:50) [10]

Так, вообщем до PostThreadMessage вроде всё правильно работает, но вот как теперь программа должна поймать это сообщение?


 
Digitman ©   (2003-10-13 16:07) [11]


> NetKnight


см. GetMessage(), PeekMessage(), MsgWaitForMultipleObjects()


 
NetKnight ©   (2003-10-17 14:04) [12]

Что-то в MSDN"е я не совсем понял, как это делается...

Вообщем вот так отсылаю сообщение из dll о том, что нужно вырубаться:

PostThreadMessage(id,WM_QUIT,0,0);

id - это переменная, которая получена приложением функцией GetCurrentThreadId и отправленная в dll.

Но вот как поймать это сообщение? Может кто-нить пример напишет, как это делается. Что-то я не догоняю.

Пробовал так:

While GetMessage (Message, 0, 0, 0) do
begin
if Message.message=WM_QUIT then exit;
end;

А как пользоваться MsgWaitForMultipleObjects() я не догнал, пример нужен :(


 
Digitman ©   (2003-10-17 14:11) [13]


> Пробовал так:
>
> While GetMessage (Message, 0, 0, 0) do
> begin
> if Message.message=WM_QUIT then exit;
> end;


в случае получения сообщения WM_QUIT строчка в теле цикла никогда не выполнится , ибо при получении данного сообщения ф-ция GetMessage() вернет False, по факту чего оператор WHILE благополучно закруглит исполнение цикла, и управление перейдет на строчку, следующую за оператором end


 
NetKnight ©   (2003-10-17 14:23) [14]

Digitman,
Но за циклом программа делает Unhook и кончается, следовательно она должна завершить выполнение. Но этого не происходит.. :(

Вот что следует далее:

While GetMessage (Message, 0, 0, 0) do
begin
if Message.message=WM_QUIT then halt;
end;
UnhookWindowsHookEx(hk);
Halt(Message.wParam);
end.


 
Digitman ©   (2003-10-17 14:54) [15]


> Но этого не происходит


я не понял - UnhookWindowsHookEx(hk) выполняется или нет ? Ты брейкпойнт ставил на эту строчку, ловил останов на ней ?


 
NetKnight ©   (2003-10-17 15:26) [16]

Всё разобрался! :)
У меня каким-то образом переданный ProcessId не соответстовал реальному.. Поправил, теперь вё заработало....
Пока GetLastError не просмотрел, бился головой о стену :)


 
Digitman ©   (2003-10-17 16:27) [17]


> Пока GetLastError не просмотрел, бился головой о стену :)


что ж мешало ? амбиции ?))



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

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

Наверх




Память: 0.51 MB
Время: 0.019 c
3-36542
Fants
2003-11-19 14:52
2003.12.12
BLOB, Jpeg, FireBird, FIBPLus


1-36661
romeo
2003-11-30 17:38
2003.12.12
Печать на принтер и превью в Win98 - какие-то странные глюки.


14-36845
iNew
2003-11-19 14:51
2003.12.12
Вопрос по русскому языку.


1-36630
prockrut
2003-12-01 02:09
2003.12.12
Cannot assign a TFont to a TFont


14-36832
Vlad Oshin
2003-11-20 10:16
2003.12.12
Что интересно, у ЮКОСа проблемы, а курс рубля вроде стоит...