程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 使用鉤子函數[1]

使用鉤子函數[1]

編輯:Delphi

目前對鉤子的理解:

譬如我們用鼠標在某個窗口上雙擊了一次, 或者給某個窗口輸入了一個字母 A;

首先發現這些事件的不是窗口, 而是系統!

然後系統告訴窗口: 喂! 你讓人點了, 並且是連續點了兩鼠標, 你准備怎麼辦?

或者是系統告訴窗口: 喂! 有人向你家裡扔磚頭了, 不信你看看, 那塊磚頭是 A.

這時窗口的對有些事件會忽略、對有些事件會做出反應:

譬如, 可能對鼠標單擊事件忽略, 窗口想: 你單擊我不要緊, 累死你我不負責;

但一旦誰要雙擊我, 我會馬上行動, 給你點顏色瞧瞧!

這裡窗口准備要采取的行動, 就是我們提前寫好的事件.

用 Windows 的話說, 窗口的事件就是系統發送給窗口的消息; 窗口要采取的行動(事件代碼)就是窗口的回調函數.

但是! 往往隔牆有耳. 系統要通知給窗口的"話"(消息), 可能會被另一個家伙(譬如是一個賊)提前聽到!

有可能這個賊就是專門在這等情報的, 賊知道後, 往往在窗口知道以前就采取了行動!

並且這個賊對不同的消息會采取不同的行動方案, 它的行動方案一般也是早就准備好的;

當然這個賊也不是對什麼消息都感興趣, 對不感興趣的消息也就無須制定相應的行動方案.

總結: 這個"賊"就是我們要設置的鉤子; "賊"的"行動方案"就是鉤子函數, 或者叫鉤子的回調函數.
鉤子分兩種, 一種是系統級的全局鉤子; 一種是線程級的鉤子.
全局鉤子函數需要定義在 DLL 中, 從線程級的鉤子開始比較簡單.

其實鉤子函數就三個:
設置鉤子: SetWindowsHookEx
釋放鉤子: UnhookWindowsHookEx
繼續鉤子: CallNextHookEx
在線程級的鉤子中經常用到 GetCurrentThreadID 函數來獲取當前線程的 ID.

下面例子中設定了一個線程級的鍵盤鉤子, 專門攔截字母 A.

unit Unit1;
interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
end;

{聲明鍵盤鉤子回調函數; 其參數傳遞方式要用 API 的 stdcall}
function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

var
Form1: TForm1;

implementation

{$R *.DFM}

var
hook: HHOOK; {定義一個鉤子句柄}

{實現鍵盤鉤子回調函數}
function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
if (wParam = 65) then Beep; {每攔截到字母 A 會發聲}
Result := CallNextHookEx(hook, nCode, wParam, lParam);
end;

{設置鍵盤鉤子}
procedure TForm1.FormCreate(Sender: TObject);
begin
hook := SetWindowsHookEx(WH_KEYBOARD, @KeyHook, 0, GetCurrentThreadID);
end;

{釋放鍵盤鉤子}
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnhookWindowsHookEx(hook);
end;

end.

盡管這個例子已經很簡單了, 但還不足以讓人明白徹底; 下面還得從更簡單的開始.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved