當前位置:首頁 » 網頁前端 » 前端開發中說的鉤子
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

前端開發中說的鉤子

發布時間: 2022-04-26 11:35:55

⑴ 編程里說的 鉤子和勺子是什麼

Windows系統中鉤子具有相當強大的功能,通過這種技術可以對幾乎所有的Windows 系統中的消息進行攔截、監視、處理。這種技術可以廣泛應用於各種軟體,尤其是需要有監控、自動記錄等對系統進行監測功能的軟體。

VB編程中鉤子的實現

(一)鉤子函數(HOOK Function)的格式。Hook Function實際上是一個函數,如果是系統鉤子,該函數必須放在動態鏈接庫中。該函數有一定的參數格式,在VB中如下:

Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long,ByVal lParam As Long)As Long

其中,nCode代表是什麼情況之下所產生的鉤子,隨鉤子的不同而有不同組的可能值;參數wParam,lParam傳回值包括了所監視到的消息內容,它隨Hook所監視消息的種類和nCode的值不同而不同。對於用VB所設置的鉤子函數,一般的框架形式如下:

Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long,ByVal lParam As Long)As Long
Select case of nCode
case ncode<0:hookfunc=callnexthookex(hHookFunc,nCode,wParam,lParam)
case值1:處理過程1:HookFunc=X1
case2:處理過程2:HookFunc=X1
……
end select
end Function

函數的傳回值,如果消息要被處理,則傳0,否則傳1,吃掉消息。

(二)鉤子的安裝及執行。鉤子的安裝要用到幾個API函數:可以使用API函數SetWindowsHookEx()把一個應用程序定義的鉤子子程安裝到鉤子鏈表中。SetWindowsHookEx()函數的聲明如下:

Declare function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA"(ByVal idHook As Long,ByVal lpfn As Long,ByVal hmod As Long,ByVal dwThreadId As Long)As Long

idHook值為它處理的消息類型;lpfn值為鉤子子程序的地址指針。如果dwThreadId參數為0或是一個由別的進程創建的線程的標識,lpfn必須指向DLL中的鉤子子程。除此以外,lpfn可以指向當前進程的一段鉤子子程代碼。hMod值為應用程序的句柄,標識包含lpfn所指的子程的DLL。如果dwThreadId標識當前進程創建的一個線程,而且子程代碼位於當前進程,hMod必須為0。dwThreadId值為與安裝的鉤子子程相關聯的線程的標識符,如果為0,鉤子子程與所有的線程關聯。鉤子安裝成功則返回鉤子子程的句柄,失敗返回0。

另外,一般應在鉤子子程中調用CallNextHookEx()函數以執行鉤子鏈表所指的下一個鉤子子程,否則安裝了別的鉤子的應用程序就會收不到鉤子通知,從而產生錯誤的結果。CallNextHookEx()函數的聲明如下:

Declare Function CallNextHookEx Lib"user32" Alias "CallNextHookEx"(ByVal hHook As Long,ByVal ncode As Lonog, ByVal wParam As Long,lParam As Any)As Long

hHook值是SetWindowsHookEx()的傳回值,nCode、wParam、lParam則是Hook函數中的三個參數。在程序終止之前,必須調用UnhookWindowsHookEx()函數釋放與鉤子關聯的系統資源。UnhookWindowsEx()函數聲明如下:

Declare Function Unhook WindowsHookEx Lib "user32" Alias "Unhook WindowsHookEx(ByVal hHook As Long)As Long

hHook為安裝鉤子時的返回值,即鉤子子程的句柄。

⑵ 程序開發中什麼是導入溝子

導入鉤子就是導入擴展內容,分為元鉤子和路徑鉤子。
導入機制被設計為可擴展;其中的基本機制是 導入鉤子。 導入鉤子有兩種類型: 元鉤子 和 導入路徑鉤子。
元鉤子在導入過程開始時被調用,此時任何其他導入過程尚未發生,但 sys.moles 緩存查找除外。 這允許元鉤子重載 sys.path 過程、凍結模塊甚至內置模塊。 元鉤子的注冊是通過向 sys.meta_path 添加新的查找器對象,具體如下所述。
導入路徑鉤子是作為 sys.path (或 package.__path__) 過程的一部分,在遇到它們所關聯的路徑項的時候被調用。 導入路徑鉤子的注冊是通過向 sys.path_hooks 添加新的可調用對象,具體如下所述。
導入機制被設計為可擴展;其中的基本機制是 導入鉤子。 導入鉤子有兩種類型: 元鉤子 和 導入路徑鉤子。
元鉤子在導入過程開始時被調用,此時任何其他導入過程尚未發生,但 sys.moles 緩存查找除外。 這允許元鉤子重載 sys.path 過程、凍結模塊甚至內置模塊。 元鉤子的注冊是通過向 sys.meta_path 添加新的查找器對象,具體如下所述。
導入路徑鉤子是作為 sys.path (或 package.__path__) 過程的一部分,在遇到它們所關聯的路徑項的時候被調用。 導入路徑鉤子的注冊是通過向 sys.path_hooks 添加新的可調用對象,具體如下所述。
導入機制被設計為可擴展;其中的基本機制是 導入鉤子。 導入鉤子有兩種類型: 元鉤子 和 導入路徑鉤子。
元鉤子在導入過程開始時被調用,此時任何其他導入過程尚未發生,但 sys.moles 緩存查找除外。 這允許元鉤子重載 sys.path 過程、凍結模塊甚至內置模塊。 元鉤子的注冊是通過向 sys.meta_path 添加新的查找器對象,具體如下所述。
導入路徑鉤子是作為 sys.path (或 package.__path__) 過程的一部分,在遇到它們所關聯的路徑項的時候被調用。 導入路徑鉤子的注冊是通過向 sys.path_hooks 添加新的可調用對象,具體如下所述。

⑶ 易語言鉤子是什麼意思

鉤子
原英文名稱 Hook ,鉤子的意思是指攔截或截獲。作用就是攔截程序中交互的數據,先經過我們預定的鉤子處理介面程序,處理過後,再交還給原處理程序,或者乾脆阻止,吃掉這些數據,讓原處理程序什麼也得不到。
鉤子原來是Windows操作系統常用來檢查系統與程序間通信的一些數據是否到達目標時用的,為不傳之密,後來隨著一些高手們的研究,逐漸的發現了這些秘密的技術並且公布了出來。同時還有更多的人在掌握了這些技術後,用在自已的軟體開發中,實現出奇招而超過其它同類軟體的功能而贏得市場。。
鉤子技術的種類上很多。

⑷ c#鉤子是什麼書上沒怎麼說,求高手詳細教教我。

鉤子(Hook),是Windows消息處理機制的一個平台,應用程序可以在上面設置子程以監視指定窗口的某種消息,而且所監視的窗口可以是其他進程所創建的。當消息到達後,在目標窗口處理函數之前處理它。鉤子機制允許應用程序截獲處理window消息或特定事件。鉤子實際上是一個處理消息的程序段,通過系統調用,把它掛入系統。每當特定的消息發出,在沒有到達目的窗口前,鉤子程序就先捕獲該消息,亦即鉤子函數先得到控制權。這時鉤子函數即可以加工處理(改變)該消息,也可以不作處理而繼續傳遞該消息,還可以強制結束消息的傳遞。

給你個C#全局鉤子參考代碼:
blog.csdn.net/speepnow/article/details/6193882

前端開發中所謂的鉤子是什麼意思

就是綁定的事件的意思(鉤子->綁定)

<button id="mes">show</button>

//js
var btn = document.getElementById('mes');

var showMes = function() {
alert('鉤子函數');
};

btn.addEventListener('click', showMes);

showMes 就是鉤子函數

⑹ 編程中常說的hook是什麼意思

就是鉤子,用於劫持消息,在windows中是這樣的,因為win32程序是以消息機制為基礎的,比如你點擊滑鼠,會給窗口傳遞一個消息,移動滑鼠,會給窗口一個消息,用鉤子可以比你的窗口先檢測到這個消息,從而得到這個消息進行處理,你的窗口可能就處理不到這個消息了,要看你的鉤子處理程序是否把這個消息傳給窗口,具體看WIN32應用程序開發吧,

⑺ 什麼時候用到鉤子(HOOK) C++,鉤子可以達到什麼目地

你既然知道鉤子,我覺得這個問題你應該知道.
鉤子是微軟windows操作系統獨有的,用以鉤取其他程序(或窗口)的消息的,(windows的消息機制就不說了 ),消息進入消息隊列時,先是被鉤子鉤走,如果沒有鉤子鉤取該消息,消息才能到達本應到達的應用程序,也就是說鉤子比應用程序擁有更高的消息獲取優先權,當然鉤子勾走了消息後還可以把消息還回去.
一般來說,鉤子應用於病毒/反病毒/外掛等特殊用途的應用程序
10分就告訴你這么多

⑻ 有種木馬程序叫「鉤子」的誰能說說原理

鉤子僅僅是一個處理消息的程序段,通過系統調用,把它自身掛入系統,每當有特定的消息發出時,沒有到達窗口前,鉤子程序就先截獲該消息。鉤子是製作木馬程序的關鍵,因為不同的鉤子可以截獲不同的信息,處理不同的任務。例如鍵盤鉤子可以截獲鍵盤記錄,而滑鼠鉤子可以截獲滑鼠的運動消息,外殼鉤子是截獲啟動和關閉應用程序消息的關鍵,而日誌鉤子則可以監視和記錄所有的輸入事件

⑼ 什麼叫鉤子過程

一、 介紹
本文將討論在.NET應用程序中全局系統鉤子的使用。為此,我開發了一個可重用的類庫並創建一個相應的示常式序(見下圖)。

你可能注意到另外的關於使用系統鉤子的文章。本文與之類似但是有重要的差別。這篇文章將討論在.NET中使用全局系統鉤子,而其它文章僅討論本地系統鉤子。這些思想是類似的,但是實現要求是不同的。
二、 背景
如果你對Windows系統鉤子的概念不熟悉,讓我作一下簡短的描述:
・一個系統鉤子允許你插入一個回調函數-它攔截某些Windows消息(例如,滑鼠相聯系的消息)。
・一個本地系統鉤子是一個系統鉤子-它僅在指定的消息由一個單一線程處理時被調用。
・一個全局系統鉤子是一個系統鉤子-它當指定的消息被任何應用程序在整個系統上所處理時被調用。
已有若干好文章來介紹系統鉤子概念。在此,不是為了重新收集這些介紹性的信息,我只是簡單地請讀者參考下面有關系統鉤子的一些背景資料文章。如果你對系統鉤子概念很熟悉,那麼你能夠從本文中得到你能夠得到的任何東西。
・關於MSDN庫中的鉤子知識。
・Dino Esposito的《Cutting Edge-Windows Hooks in the .NET Framework》。
・Don Kackman的《在C#中應用鉤子》。
本文中我們要討論的是擴展這個信息來創建一個全局系統鉤子-它能被.NET類所使用。我們將用C#和一個DLL和非託管C++來開發一個類庫-它們一起將完成這個目標。
三、 使用代碼
在我們深入開發這個庫之前,讓我們快速看一下我們的目標。在本文中,我們將開發一個類庫-它安裝全局系統鉤子並且暴露這些由鉤子處理的事件,作為我們的鉤子類的一個.NET事件。為了說明這個系統鉤子類的用法,我們將在一個用C#編寫的Windows表單應用程序中創建一個滑鼠事件鉤子和一個鍵盤事件鉤子。
這些類庫能用於創建任何類型的系統鉤子,其中有兩個預編譯的鉤子-MouseHook和KeyboardHook。我們也已經包含了這些類的特定版本,分別稱為MouseHookExt和KeyboardHookExt。根據這些類所設置的模型,你能容易構建系統鉤子-針對Win32 API中任何15種鉤子事件類型中的任何一種。另外,這個完整的類庫中還有一個編譯的HTML幫助文件-它把這些類歸檔化。請確信你看了這個幫助文件-如果你決定在你的應用程序中使用這個庫的話。
MouseHook類的用法和生命周期相當簡單。首先,我們創建MouseHook類的一個實例。

mouseHook = new MouseHook();//mouseHook是一個成員變數
接下來,我們把MouseEvent事件綁定到一個類層次的方法上。

mouseHook.MouseEvent+=new MouseHook.MouseEventHandler(mouseHook_MouseEvent);
// ...
private void mouseHook_MouseEvent(MouseEvents mEvent, int x, int y){
string msg =string.Format("滑鼠事件:{0}:({1},{2}).",mEvent.ToString(),x,y);
AddText(msg);//增加消息到文本框
}
為開始收到滑鼠事件,簡單地安裝下面的鉤子即可。

mouseHook.InstallHook();
為停止接收事件,只需簡單地卸載這個鉤子。

mouseHook.UninstallHook();
你也可以調用Dispose來卸載這個鉤子。
在你的應用程序退出時,卸載這個鉤子是很重要的。讓系統鉤子一直安裝著將減慢系統中的所有的應用程序的消息處理。它甚至能夠使一個或多個進程變得很不穩定。因此,請確保在你使用完鉤子時一定要移去你的系統鉤子。我們確定在我們的示例應用程序會移去該系統鉤子-通過在Form的Dispose方法中添加一個Dispose調用。

protected override void Dispose(bool disposing) {
if (disposing) {
if (mouseHook != null) {
mouseHook.Dispose();
mouseHook = null;
}
// ...
}
}
使用該類庫的情況就是如此。該類庫中有兩個系統鉤子類並且相當容易擴充。
四、 構建庫
這個庫共有兩個主要組件。第一部分是一個C#類庫-你可以直接使用於你的應用程序中。該類庫,反過來,在內部使用一個非託管的C++ DLL來直接管理系統鉤子。我們將首先討論開發該C++部分。接下來,我們將討論怎麼在C#中使用這個庫來構建一個通用的鉤子類。就象我們討論C++/C#交互一樣,我們將特別注意C++方法和數據類型是怎樣映射到.NET方法和數據類型的。
你可能想知道為什麼我們需要兩個庫,特別是一個非託管的C++ DLL。你還可能注意到在本文的背景一節中提到的兩篇參考文章,其中並沒有使用任何非託管的代碼。為此,我的回答是,"對!這正是我寫這篇文章的原因"。當你思考系統鉤子是怎樣實際地實現它們的功能時,我們需要非託管的代碼是十分重要的。為了使一個全局的系統鉤子能夠工作,Windows把你的DLL插入到每個正在運行的進程的進程空間中。既然大多數進程不是.NET進程,所以,它們不能直接執行.NET裝配集。我們需要一種非託管的代碼代理- Windows可以把它插入到所有將要被鉤住的進程中。
首先是提供一種機制來把一個.NET代理傳遞到我們的C++庫。這樣,我們用C++語言定義下列函數(SetUserHookCallback)和函數指針(HookProc)。

int SetUserHookCallback(HookProc userProc, UINT hookID)
typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l)
SetUserHookCallback的第二個參數是鉤子類型-這個函數指針將使用它。現在,我們必須用C#來定義相應的方法和代理以使用這段代碼。下面是我們怎樣把它映射到C#。

private static extern SetCallBackResults
SetUserHookCallback(HookProcessedHandler hookCallback, HookTypes hookType)
protected delegate void HookProcessedHandler(int code, UIntPtr wparam, IntPtr lparam)
public enum HookTypes {
JournalRecord = 0,
JournalPlayback = 1,
// ...
KeyboardLL = 13,
MouseLL = 14
};
首先,我們使用DllImport屬性導入SetUserHookCallback函數,作為我們的抽象基鉤子類SystemHook的一個靜態的外部的方法。為此,我們必須映射一些外部數據類型。首先,我們必須創建一個代理作為我們的函數指針。這是通過定義上面的HookProcessHandler 來實現的。我們需要一個函數,它的C++簽名為(int,WPARAM,LPARAM)。在Visual Studio .NET C++編譯器中,int與C#中是一樣的。也就是說,在C++與C#中int就是Int32。事情並不總是這樣。一些編譯器把C++ int作為Int16對待。我們堅持使用Visual Studio .NET C++編譯器來實現這個工程,因此,我們不必擔心編譯器差別所帶來的另外的定義。
接下來,我們需要用C#傳遞WPARAM和LPARAM值。這些確實是指針,它們分別指向C++的UINT和LONG值。用C#來說,它們是指向uint和int的指針。如果你還不確定什麼是WPARAM,你可以通過在C++代碼中單擊右鍵來查詢它,並且選擇"Go to definition"。這將會引導你到在windef.h中的定義。

//從windef.h:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
因此,我們選擇System.UIntPtr和System.IntPtr作為我們的變數類型-它們分別相應於WPARAM和LPARAM類型,當它們使用在C#中時。
現在,讓我們看一下鉤子基類是怎樣使用這些導入的方法來傳遞一個回叫函數(代理)到C++中-它允許C++庫直接調用你的系統鉤子類的實例。首先,在構造器中,SystemHook類創建一個到私有方法InternalHookCallback的代理-它匹配HookProcessedHandler代理簽名。然後,它把這個代理和它的HookType傳遞到C++庫以使用SetUserHookCallback方法來注冊該回叫函數,如上面所討論的。下面是其代碼實現:

public SystemHook(HookTypes type){
_type = type;
_processHandler = new HookProcessedHandler(InternalHookCallback);
SetUserHookCallback(_processHandler, _type);
}
InternalHookCallback的實現相當簡單。InternalHookCallback在用一個catch-all try/catch塊包裝它的同時僅傳遞到抽象方法HookCallback的調用。這將簡化在派生類中的實現並且保護C++代碼。記住,一旦一切都准備妥當,這個C++鉤子就會直接調用這個方法。

[MethodImpl(MethodImplOptions.NoInlining)]
private void InternalHookCallback(int code, UIntPtr wparam, IntPtr lparam){
try { HookCallback(code, wparam, lparam); }
catch {}
}
我們已增加了一個方法實現屬性-它告訴編譯器不要內聯這個方法。這不是可選的。至少,在我添加try/catch之前是需要的。看起來,由於某些原因,編譯器在試圖內聯這個方法-這將給包裝它的代理帶來各種麻煩。然後,C++層將回叫,而該應用程序將會崩潰。
現在,讓我們看一下一個派生類是怎樣用一個特定的HookType來接收和處理鉤子事件。下面是虛擬的MouseHook類的HookCallback方法實現:

protected override void HookCallback(int code, UIntPtr wparam, IntPtr lparam){
if (MouseEvent == null) { return; }
int x = 0, y = 0;
MouseEvents mEvent = (MouseEvents)wparam.ToUInt32();
switch(mEvent) {
case MouseEvents.LeftButtonDown:
GetMousePosition(wparam, lparam, ref x, ref y);
break;
// ...
}
MouseEvent(mEvent, new Point(x, y));
}
首先,注意這個類定義一個事件MouseEvent-該類在收到一個鉤子事件時激發這個事件。這個類在激發它的事件之前,把數據從WPARAM和 LPARAM類型轉換成.NET中有意義的滑鼠事件數據。這樣可以使得類的消費者免於擔心解釋這些數據結構。這個類使用導入的 GetMousePosition函數-我們在C++ DLL中定義的用來轉換這些值。為此,請看下面幾段的討論。
在這個方法中,我們檢查是否有人在聽這一個事件。如果沒有,不必繼續處理這一事件。然後,我們把WPARAM轉換成一個MouseEvents枚舉類型。我們已小心地構造了MouseEvents枚舉來准確匹配它們在C ++中相應的常數。這允許我們簡單地把指針的值轉換成枚舉類型。但是要注意,這種轉換即使在WPARAM的值不匹配一個枚舉值的情況下也會成功。 mEvent的值將僅是未定義的(不是null,只是不在枚舉值范圍之內)。為此,請詳細分析System.Enum.IsDefined方法。
接下來,在確定我們收到的事件類型後,該類激活這個事件,並且通知消費者滑鼠事件的類型及在該事件過程中滑鼠的位置。
最後注意,有關轉換WPARAM和LPARAM值:對於每個類型的事件,這些變數的值和意思是不同的。因此,在每一種鉤子類型中,我們必須區別地解釋這些值。我選擇用C++實現這種轉換,而不是盡量用C#來模仿復雜的C++結構和指針。例如,前面的類就使用了一個叫作GetMousePosition的 C++函數。下面是C++ DLL中的這個方法:

bool GetMousePosition(WPARAM wparam, LPARAM lparam, int amp; x, int amp; y) {
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam;
x = pMouseStruct->pt.x;
y = pMouseStruct->pt.y;
return true;
}
不是盡量映射MOUSEHOOKSTRUCT結構指針到C#,我們簡單地暫時把它回傳到C++層以提取我們需要的值。注意,因為我們需要從這個調用中返回一些值,我們把我們的整數作為參考變數傳遞。這直接映射到C#中的int*。但是,我們可以重載這個行為,通過選擇正確的簽名來導入這個方法。

private static extern bool InternalGetMousePosition(UIntPtr wparam,IntPtr lparam, ref int x, ref int y)
通過把integer參數定義為ref int,我們得到通過C++參照傳遞給我們的值。如果我們想要的話,我們還可以使用out int。
五、 限制
一些鉤子類型並不適合實現全局鉤子。我當前正在考慮解決辦法-它將允許使用受限制的鉤子類型。到目前為止,不要把這些類型添加回該庫中,因為它們將導致應用程序的失敗(經常是系統范圍的災難性失敗)。下一節將集中討論這些限制背後的原因和解決辦法。

HookTypes.CallWindowProcere
HookTypes.CallWindowProret
HookTypes.ComputerBasedTraining
HookTypes.Debug
HookTypes.ForegroundIdle
HookTypes.JournalRecord
HookTypes.JournalPlayback
HookTypes.GetMessage
HookTypes.SystemMessageFilter
六、 兩種類型的鉤子
在本節中,我將盡量解釋為什麼一些鉤子類型被限制在一定的范疇內而另外一些則不受限制。如果我使用有點偏差術語的話,請原諒我。我還沒有找到任何有關這部分題目的文檔,因此,我編造了我自己的詞彙。另外,如果你認為我根本就不對,請告訴我好了。
當Windows調用傳遞到SetWindowsHookEx()的回調函數時它們會因不同類型的鉤子而被區別調用。基本上有兩種情況:切換執行上下文的鉤子和不切換執行上下文的鉤子。用另一種方式說,也就是,在放鉤子的應用程序進程空間執行鉤子回調函數的情況和在被鉤住的應用程序進程空間執行鉤子回調函數的情況。
鉤子類型例如滑鼠和鍵盤鉤子都是在被Windows調用之前切換上下文的。整個過程大致如下:
1. 應用程序X擁有焦點並執行。
2. 用戶按下一個鍵。
3. Windows從應用程序X接管上下文並把執行上下文切換到放鉤子的應用程序。
4. Windows用放鉤子的應用程序進程空間中的鍵消息參數調用鉤子回調函數。
5. Windows從放鉤子的應用程序接管上下文並把執行上下文切換回應用程序X。
6. Windows把消息放進應用程序X的消息排隊。
7. 稍微一會兒之後,當應用程序X執行時,它從自己的消息排隊中取出消息並且調用它的內部按鍵(或松開或按下)處理器。
8. 應用程序X繼續執行...
例如CBT鉤子(window創建,等等。)的鉤子類型並不切換上下文。對於這些類型的鉤子,過程大致如下:
1. 應用程序X擁有焦點並執行。
2. 應用程序X創建一個窗口。
3. Windows用在應用程序X進程空間中的CBT事件消息參數調用鉤子回調函數。
4. 應用程序X繼續執行...
這應該說明了為什麼某種類型的鉤子能夠用這個庫結構工作而一些卻不能。記住,這正是該庫要做的。在上面第4步和第3步之後,分別插入下列步驟:
1. Windows調用鉤子回調函數。
2. 目標回調函數在非託管的DLL中執行。
3. 目標回調函數查找它的相應託管的調用代理。
4. 託管代理被以適當的參數執行。
5. 目標回調函數返回並執行相應於指定消息的鉤子處理。
第三步和第四步因非切換鉤子類型而註定失敗。第三步將失敗,因為相應的託管回調函數不會為該應用程序而設置。記住,這個DLL使用全局變數來跟蹤這些託管代理並且該鉤子DLL被載入到每一個進程空間。但是這個值僅在放鉤子的應用程序進程空間中設置。對於另外其它情況,它們全部為null。
Tim Sylvester在他的《Other hook types》一文中指出,使用一個共享內存區段將會解決這個問題。這是真實的,但是也如Tim所指出的,那些託管代理地址對於除了放鉤子的應用程序之外的任何進程是無意義的。這意味著,它們是無意義的並且不能在回調函數的執行過程中調用。那樣會有麻煩的。
因此,為了把這些回調函數使用於不執行上下文切換的鉤子類型,你需要某種進程間的通訊。
我已經試驗過這種思想-使用非託管的DLL鉤子回調函數中的進程外COM對象進行IPC。如果你能使這種方法工作,我將很高興了解到這點。至於我的嘗試,結果並不理想。基本原因是很難針對各種進程和它們的線程(CoInitialize(NULL))而正確地初始化COM單元。這是一個在你可以使用 COM對象之前的基本要求。
我不懷疑,一定有辦法來解決這個問題。但是我還沒有試用過它們,因為我認為它們僅有有限的用處。例如,CBT鉤子可以讓你取消一個窗口創建,如果你希望的話。可以想像,為使這能夠工作將會發生什麼。
1. 鉤子回調函數開始執行。
2. 調用非託管的鉤子DLL中的相應的鉤子回調函數。
3. 執行必須被路由回到主鉤子應用程序。
4. 該應用程序必須決定是否允許這一創建。
5. 調用必須被路由回仍舊在運行中的鉤子回調函數。
6. 在非託管的鉤子DLL中的鉤子回調函數從主鉤子應用程序接收到要採取的行動。
7. 在非託管的鉤子DLL中的鉤子回調函數針對CBT鉤子調用採取適當的行動。
8. 完成鉤子回調函數的執行。
這不是不可能的,但是不算好的。我希望這會消除在該庫中的圍繞被允許的和受限制的鉤子類型所帶來的神秘。
七、 其它
・庫文檔:我們已經包含了有關ManagedHooks類庫的比較完整的代碼文檔。當以"Documentation"構建配置進行編譯時,這被經由Visual Studio.NET轉換成標准幫助XML。最後,我們已使用NDoc來把它轉換成編譯的HTML幫助(CHM)。你可以看這個幫助文件,只需簡單地在該方案的解決方案資源管理器中點擊Hooks.chm文件或通過查找與該文相關的可下載的ZIP文件。
・增強的智能感知:如果你不熟悉Visual Studio.NET怎樣使用編譯的XML文件(pre-NDoc output)來為參考庫的工程增強智能感知,那麼讓我簡單地介紹一下。如果你決定在你的應用程序中使用這個類庫,你可以考慮復制該庫的一個穩定構建版本到你想參考它的位置。同時,還要把XML文檔文件 (SystemHooks\ManagedHooks\bin\Debug\Kennedy.ManagedHooks.xml)復制到相同的位置。當你添加一個參考到該庫時,Visual Studio.NET將自動地讀該文件並使用它來添加智能感知文檔。這是很有用的,特別是對於象這樣的第三方庫。
・單元測試:我相信,所有的庫都應有與之相應的單元測試。既然我是一家公司(主要負責針對.NET環境軟體的單元測試)的合夥人和軟體工程師,任何人不會對此感到驚訝。因而,你將會在名為ManagedHooksTests的解決方案中找到一個單元測試工程。為了運行該單元測試,你需要下載和安裝 HarnessIt-這個下載是我們的商業單元測試軟體的一個自由的試用版本。在該單元測試中,我對這給予了特殊的注意-在此處,方法的無效參數可能導致 C++內存異常的發生。盡管這個庫是相當簡單的,但該單元測試確實能夠幫助我在一些更為微妙的情況下發現一些錯誤。
・非託管的/託管的調試:有關混合解決方案(例如,本文的託管的和非託管的代碼)最為技巧的地方之一是調試問題。如果你想單步調試該C++代碼或在C++代碼中設置斷點,你必須啟動非託管的調試。這是一個Visual Studio.NET中的工程設置。注意,你可以非常順利地單步調試託管的和非託管的層,但是,在調試過程中,非託管的調試確實嚴重地減慢應用程序的裝載時間和執行速度。
八、 最後警告
很明顯,系統鉤子相當有力量;然而,使用這種力量應該是有責任性的。在系統鉤子出了問題時,它們不僅僅垮掉你的應用程序。它們可以垮掉在你的當前系統中運行的每個應用程序。但是到這種程度的可能性一般是很小的。盡管如此,在使用系統鉤子時,你還是需要再三檢查你的代碼。
我發現了一項可以用來開發應用程序的有用的技術-它使用系統鉤子來在微軟的虛擬PC上安裝你的喜愛的開發操作系統的一個拷貝和Visual Studio.NET。然後,你就可以在此虛擬的環境中開發你的應用程序。用這種方式,當你的鉤子應用程序出現錯誤時,它們將僅退出你的操作系統的虛擬實例而不是你的真正的操作系統。我已經不得不重啟動我的真正的OS-在這個虛擬OS由於一個鉤子錯誤崩潰時,但是這並不經常。