为了显示效果,在钩子的DLL中我们会获取挂钩函数的窗体句柄,这里的主程序窗体名为"TestMain",通过FindWindow查找。
KeyBoardHook.dll代码
1 library KeyBoardHook; 2 3 { Important note about DLL memory management: ShareMem must be the 4 first unit in your library's USES clause AND your project's (select 5 Project-View Source) USES clause if your DLL exports any procedures or 6 functions that pass strings as parameters or function results. This 7 applies to all strings passed to and from your DLL--even those that 8 are nested in records and classes. ShareMem is the interface unit to 9 the BORLNDMM.DLL shared memory manager, which must be deployed along 10 with your DLL. To avoid using BORLNDMM.DLL, pass string information 11 using PChar or ShortString parameters. } 12 13 uses 14 SysUtils,Windows,Messages, 15 Classes; 16 17 var 18 fHook:HHOOK; 19 //执行挂钩程序的窗体句柄 20 CallHandle:HWND; 21 22 {$R *.res} 23 24 //回调过程 25 function HookProc(code:Integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall; 26 var 27 processid:Cardinal; 28 begin 29 //如果有键盘动作 30 if code = HC_Action then 31 begin 32 //获取注入进程的进程id 33 processid := GetCurrentProcessId; 34 //如果CallHandle,则查找TestMain窗体句柄 35 if CallHandle = 0 then 36 CallHandle := FindWindow(nil,'TestMain'); 37 //获取按键状态 小于0表示按下,如果不做判断,按键按下或抬起都会执行SendMessage 38 //下面发送WM_USER+101消息,此消息可以用自定义的消息标识发送 39 if GetKeyState(wParam) < 0 then 40 SendMessage(CallHandle,WM_USER+101,wParam,processid); 41 end 42 else 43 //下一个钩子 44 Result := CallNextHookEx(fHook,code,wParam,lParam); 45 end; 46 47 procedure SetHook;stdcall; 48 begin 49 //挂钩,这里没有做挂钩失败的提示 50 fHook := SetWindowsHookEx(WH_KEYBOARD,@HookProc,HInstance,0); 51 end; 52 53 procedure StopHook;stdcall; 54 begin 55 //摘钩 56 if fHook <> 0 then 57 UnhookWindowsHookEx(fHook); 58 end; 59 60 exports 61 SetHook name 'SetHook', 62 StopHook name 'StopHook'; 63 64 begin 65 //初始CallHandle为0 66 CallHandle := 0; 67 end.
TestKeyBoardHook主程序代码
{ 此窗体用来执行挂钩,为了方便起见,我们把系统的按键返回到该窗体的Memo组件中进行 显示,所以在dll中,做了获取主窗体的句柄的工作,以便发消息给主窗体,告诉它是哪个 按键被按下 } unit TestMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,TlHelp32; type TfrmTestMain = class(TForm) Memo1: TMemo; btn_SetHook: TButton; btn_StopHook: TButton; procedure btn_SetHookClick(Sender: TObject); procedure btn_StopHookClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } procedure WndProc(var Message: TMessage);override; public { Public declarations } end; var frmTestMain: TfrmTestMain; implementation procedure SetHook;stdcall;external 'KeyBoardHook'; procedure StopHook;stdcall;external 'KeyBoardHook'; {$R *.dfm} procedure TfrmTestMain.btn_SetHookClick(Sender: TObject); begin SetHook; end; procedure TfrmTestMain.btn_StopHookClick(Sender: TObject); begin StopHook; end; procedure TfrmTestMain.WndProc(var Message: TMessage); var hSnapShot:THandle; pEntry:TProcessEntry32; find:Boolean; proName:string; begin if Message.Msg = WM_USER+101 then begin //创建进程快照 hSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); pEntry.dwSize := SizeOf(pEntry); find := Process32First(hSnapShot,pEntry); while find do begin //取进程名字 proName := pEntry.szExeFile; if pEntry.th32ProcessID = Message.LParam then Break; find := Process32Next(hSnapShot,pEntry); end; Memo1.Lines.Add('进程:' + proName + ',ID:' +IntToStr(Message.LParam)+'按下按键:'+Chr(Message.WParam)); CloseHandle(hSnapShot); end; inherited; end; procedure TfrmTestMain.FormClose(Sender: TObject; var Action: TCloseAction); begin StopHook; end; end.