學(xué)用鉤子函數(shù)
鉤子函數(shù)并不是什么高深的技術(shù),在Microsoft的Win32
SDK手冊(cè)上就有記述。不過(guò)很可惜秉承M$的一貫風(fēng)格,要看懂可是不容易的事!而且它的例子是使用SDK寫的,又不完整!這就讓我們這些用只會(huì)
Delphi的程序員更看不懂了。不過(guò)用鉤子函數(shù)是很有用的,例如鼠標(biāo)鉤子可以攔截下所有的鼠標(biāo)消息的。
前段時(shí)間我寫我的第一個(gè)軟件《聊天快貼》的時(shí)候,學(xué)習(xí)了一下鼠標(biāo)鉤子函數(shù),現(xiàn)在我把我?guī)字艿膶W(xué)習(xí)成果寫出來(lái)希望對(duì)大家有幫助。
鉤子函數(shù)一共有12種(這里就不列舉出來(lái)了,不過(guò)說(shuō)實(shí)話我多數(shù)鉤子也沒(méi)有用過(guò)^_^),分為全局子和線程鉤子兩種。線程鉤子就只監(jiān)視某個(gè)線程,全局鉤子可
以監(jiān)視Windows的所有線程。具體的你可以看看Delphi 帶的Win32
SDK,就是是全英文的,可惜了。全局鉤子是必須用DLL加載,也就是說(shuō)鉤子函數(shù)這部分必須包裝為一個(gè)DLL文件,然后再在主程序中調(diào)用鉤子DLL中函數(shù)
才可以!而且有些鉤子是必須以全局鉤子的方式存在,也就是一定要用DLL包裝它才可以。
再解釋一下設(shè)置鉤子的Api函數(shù):
function
SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST;
dwThreadId: DWORD): HHOOK;
stdcall;這是在Delphi下的說(shuō)明,其中第一個(gè)參數(shù)是鉤子的類型;第二個(gè)參數(shù)是鉤子函數(shù)的地址;第個(gè)參數(shù)是包含鉤子函數(shù)的模塊句柄;第四個(gè)參數(shù)
指定監(jiān)視的線程;返回鉤子句柄。如果指定了某個(gè)確定的線程就只監(jiān)視那個(gè)線程,即是線程鉤子;如果為空,即是監(jiān)視所有線程的全局鉤子。其它幾個(gè)相關(guān)函數(shù)就沒(méi)
有什么講的了,只要照著用就可以了。具體的看我的源程序吧!
另外如果你只想使用進(jìn)程鉤子的話,有一個(gè)現(xiàn)成的控件可以用,就是Rx的RxWindowHook控件。拖到你窗體上,設(shè)置Active為True就可以
了。
然后他只有BeforeMessage(消息從消息隊(duì)列取走前)和AfterMessage(消息從消息隊(duì)列取走后)兩個(gè)事件,響應(yīng)他就可以了,怎么用就
看你的了。
下面我說(shuō)說(shuō)比較實(shí)用的全局鉤子的使用!我寫了一個(gè)最簡(jiǎn)單的鼠標(biāo)全局鉤子的例子,我還假定你懂如何寫DLL。好了,來(lái)看源程序:(BTW:我學(xué)習(xí)編程技巧的時(shí)候總是想看一些最簡(jiǎn)單的例子,可是有些作者習(xí)慣用復(fù)雜的應(yīng)用作為例子。學(xué)起來(lái)真是痛苦!?。。?
一、DLL的工程文件。
library hookprj;
uses
SysUtils,
Classes,
hkprocunit in ‘hkprocunit.pas‘;
{$R *.RES}
exports
EnableMouseHook, //只要把這兩個(gè)函數(shù)輸出就可以了,
DisableMouseHook;//不會(huì)不懂函數(shù)的意思吧^_^。
begin
end.
二、DLL輸出函數(shù)的實(shí)現(xiàn)單元。
unit hkprocunit;
interface
uses
Windows,Messages;
var
hHk: HHOOK;//鉤子的句柄值。
function MouseHookProc(nCode: Integer;WParam: WPARAM;LParam: LPARAM): LRESULT;stdcall;
//鼠標(biāo)鉤子的回調(diào)函數(shù),即是用它來(lái)處理得到消息后要干什么。這里我只是發(fā)送 一個(gè)//WM_PASTE消息。
//nCode參數(shù)是Hook的標(biāo)志,一般只關(guān)心小于0時(shí)。看下面的詳細(xì)說(shuō)明
//WParam參數(shù)表示鼠標(biāo)消息的類型
//LParam參數(shù)是一個(gè)指向 TMOUSEHOOKSTRUCT 結(jié)構(gòu)的指針。結(jié)構(gòu)包含了鼠標(biāo)消息的狀態(tài),我只用了hwnd一個(gè)
//即鼠標(biāo)消息要傳遞給的窗口句柄。
//返回值如果不是0的話windows就把這個(gè)消息丟掉,其它的程序就不會(huì)再收到這個(gè)消息了。
function EnableMouseHook:Boolean; stdcall; export;
function DisableMouseHook:Boolean; stdcall; export;//兩個(gè)函數(shù)都是Boolean類型,成功都是返回True
implementation
function MouseHookProc(nCode: Integer;WParam: WPARAM;LParam: LPARAM): LRESULT;stdcall;
var
MouseHookStruct: ^TMOUSEHOOKSTRUCT;//這個(gè)結(jié)構(gòu)Delphi在Windows單元有定義,直接用就可以了。
nState: SHORT;//得到鍵盤狀態(tài)的GetKeyState函數(shù)的返回值。這是一個(gè)16位的數(shù)。
begin
Result := 0; //最好首先給他一個(gè)返回值,不然會(huì)有警告的!記住這可不是C語(yǔ)言。
//當(dāng)nCode小于0時(shí)表示還有其它的Hook,必須把參數(shù)傳給他。
//此時(shí)就要用Api函數(shù)CallNextHookEx讓他調(diào)用下一個(gè)Hook!!!當(dāng)然不用好像也可以。
if nCode < 0 then
Result := CallNextHookEx(hHk,nCode,WParam,LParam)//參數(shù)是現(xiàn)成的,直接用就可以了,詳細(xì)的說(shuō)明可以參考Win32 SDK
else if wParam = WM_LBUTTONDBLCLK then //判斷是不是鼠標(biāo)左鍵雙擊事件
begin
nState := GetKeyState(VK_CONTROL);//這個(gè)函數(shù)只有一個(gè)參數(shù),就是要得到的鍵的鍵值,這里用windows的虛擬鍵值表示ctrl鍵。
if (nState and $8000) = $8000 then//如果按下了,那么返回值的最高位為1
begin //即是16進(jìn)制的8000,如果沒(méi)有按下就返回0
MouseHookStruct := Pointer(LParam);//轉(zhuǎn)換指針并付值給MouseHookStruct變量。
SendMessage(MouseHookStruct.hwnd,WM_PASTE,0,0);//如果條件都滿足了就發(fā)送WM_PASTE(粘貼)消息
end;
end;
end;
function EnableMouseHook:Boolean; stdcall; export;
begin
if hHk = 0 then //為了安全,必須判斷一下再設(shè)置鉤子。
begin
// 第三個(gè)參數(shù)的Hinstance 在Delphi中有定義,用就可以了。第四個(gè)參數(shù)必須為0
hHk := SetWindowsHookEx(WH_MOUSE,@MouseHookProc,Hinstance,0);
Result := True;
end
else
Result := False;
end;
function DisableMouseHook:Boolean; stdcall; export;
begin
if hHk <> 0 then //如果有鉤子就卸掉他。
begin
UnHookWindowsHookEx(hHk);
hHk := 0;
Result := True;
end
else
Result := False;
end;
end.
三、使用鉤子的應(yīng)用程序的工程文件。
program Project1;
uses
Forms,
Unit1 in ‘Unit1.pas‘ {Form1};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
四、使用鉤子的應(yīng)用程序代碼。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, RxHook;
type
TForm1 = class(TForm)
Button1: TButton;//放上兩個(gè)Button和一個(gè)Edit控鍵用來(lái)試用我們的鉤子函數(shù)。
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
//下面是引用hookprj.dll中的函數(shù)。
function EnableMouseHook:Boolean; stdcall; external ‘Hookprj.dll‘ name ‘EnableMouseHook‘;
function DisableMouseHook:Boolean; stdcall; external ‘Hookprj.dll‘ name ‘DisableMouseHook‘;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
if EnableMouseHook then
ShowMessage(‘啟動(dòng)鉤子成功‘);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if DisableMouseHook then
ShowMessage(‘停止鉤子成功‘);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//這里調(diào)用是必須的,否則有可能沒(méi)有卸載鉤子就退出了,那就不好了。
DisableMouseHook;
end;
end.
Windows2000 + Delphi5.0sp1 測(cè)試通過(guò)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1175414