Форум: "WinAPI";
Текущий архив: 2003.12.12;
Скачать: [xml.tar.bz2];
ВнизПередать хенда программы в 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 вся ветка
Форум: "WinAPI";
Текущий архив: 2003.12.12;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.008 c