winform中的hook使用

       winform中的hook使用windows

在winform程序中,有時須要咱們攔截一些全局事件,好比攔截全局的鼠標事件,這個時候會用到一個windows的API來實現,這就是Hook(鉤子)。鉤子有13種類型,咱們能夠根據須要來進行全局攔截。須要注意的是,Hook是一個鏈式結構,因此咱們在進行Hookd的設置時須要在添加Hook同時別忘了將後續的Hook鏈上已保證其正確,固然要是就一個Hook的話也能夠偷偷懶的。
   系統鉤子主要是由三個API組成:
一、SetWindowsHookEx方法是將一個被應用程序定義的鉤子程序添加到鉤子鏈中,這個鉤子程序能夠監聽系統類型的事件,這些事件鏈接到一個特殊的線程中。
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, int dwThreadId);
二、UnhookWindowsHookEx方法是在鉤子鏈中刪除經過「SetWindowsHookEx」方法添加的鉤子程序。
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
三、CallNextHookEx方法是在當前的鉤子鏈中將鉤子程序信息傳遞到下一個鉤子程序中。一個鉤子程序能夠經過此方法呼叫上一個或者下一個鉤子程序的信息。
[DllImport("user32", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
   這次我這就以一個鼠標鉤子還舉例以方便你們的理解。
   首先咱們在一個按鈕中開啓鉤子
private const int WH_MOUSE_LL = 0x000E;
private IntPtr MouseHookHandle = IntPtr.Zero;
app

/// MouseHookProcedure是回調的函數ide

private static LowLevelMouseProc MouseHookProcedure =
           (int nCode, IntPtr wParam, IntPtr lParam) =>
           {
               if (nCode >= 0 && MouseEventKeys.Contains(wParam.ToInt32()))
               {
                   MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                   if (OnMouseHookEvent != null)
                   {
函數

                       /// 此處是須要拋出的事件(必須是靜態事件,由於動態事件的話會被回收站回收)
                       OnMouseHookEvent(hookStruct);
                   }
               }
               return CallNextHookEx(MouseHookHandle, nCode, wParam, lParam);
           };
佈局

public void HookStart()
{
   if (this.MouseHookHandle.ToInt32() == 0)
   {
ui

       /// 咱們經過SetWindowsHookEx方法將一個拉姆達表達式傳入,當系統截獲相關事件時則此方法進行響應。        this

       this.MouseHookHandle =
       SetWindowsHookEx(
           WH_MOUSE_LL,
           MouseHookProcedure,
           System.Diagnostics.Process.GetCurrentProcess().MainModule.BaseAddress,
           0);
       if (this.MouseHookHandle == IntPtr.Zero)
       {
           HookStop();
           throw new Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
       }
   }
}
   在打開鉤子時咱們還須要使用到CallNextHookEx方法,這是爲了在當前的鉤子鏈中將鉤子程序信息傳遞到下一個鉤子程序中。注意:若是此處須要攔截住鉤子鏈的話返回1就能夠中斷鉤子鏈,返回0則結束鉤子鏈。此處最好使用CallNextHookEx方法,由於你不知道你的整個程序是否是就你寫的惟一一個鉤子。
spa

MouseHookStruct鼠標鉤子返回數據的結構體
[StructLayout(LayoutKind.Sequential)]
public class MSLLHOOKSTRUCT
線程

{指針

   public POINT pt;
   public uint mouseData;
   public uint flags;
   public uint time;
   public IntPtr dwExtraInfo;

}
/// <summary>
/// Declare wrapper managed POINT class.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
   public int x;
   public int y;
}

   在使用鉤子完必定要關掉鉤子,切忌:要否則不停循環攔截的鉤子鏈程序要會讓你的系統變得奇慢無比。
public void HookStop()
{
   bool retMouse = true;
   if (this.MouseHookHandle != IntPtr.Zero)
   {
       retMouse = UnhookWindowsHookEx(this.MouseHookHandle);
       this.MouseHookHandle = IntPtr.Zero;
   }
   if (!retMouse) throw new Exception("UnhookWindowsHookEx failed.");
}

  鉤子的類型有13種,這裏介紹一下:上面的程序用的就是WH_MOUSE_LL Hook監視輸入到線程消息隊列中的鼠標消息。一、WH_CALLWNDPROC和WH_CALLWNDPROCRET HooksWH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你能夠監視發送到窗口過程的消息。系統在消息發送到接收窗口過程以前調用WH_CALLWNDPROC Hook子程,而且在窗口過程處理完消息以後調用WH_CALLWNDPROCRET Hook子程。WH_CALLWNDPROCRET Hook傳遞指針到CWPRETSTRUCT結構,再傳遞到Hook子程。CWPRETSTRUCT結構包含了來自處理消息的窗口過程的返回值,一樣也包括了與這個消息關聯的消息參數。二、WH_CBT Hook在如下事件以前,系統都會調用WH_CBT Hook子程,這些事件包括:    1. 激活,創建,銷燬,最小化,最大化,移動,改變尺寸等窗口事件;    2. 完成系統指令;    3. 來自系統消息隊列中的移動鼠標,鍵盤事件;    4. 設置輸入焦點事件;    5. 同步系統消息隊列事件。Hook子程的返回值肯定系統是否容許或者防止這些操做中的一個。三、WH_DEBUG Hook在系統調用系統中與其餘Hook關聯的Hook子程以前,系統會調用WH_DEBUG Hook子程。你可使用這個Hook來決定是否容許系統調用與其餘Hook關聯的Hook子程。四、WH_FOREGROUNDIDLE Hook當應用程序的前臺線程處於空閒狀態時,可使用WH_FOREGROUNDIDLE Hook執行低優先級的任務。當應用程序的前臺線程大概要變成空閒狀態時,系統就會調用WH_FOREGROUNDIDLE Hook子程。五、WH_GETMESSAGE Hook應用程序使用WH_GETMESSAGE Hook來監視從GetMessage or PeekMessage函數返回的消息。你可使用WH_GETMESSAGE Hook去監視鼠標和鍵盤輸入,以及其餘發送到消息隊列中的消息。六、WH_JOURNALPLAYBACK HookWH_JOURNALPLAYBACK Hook使應用程序能夠插入消息到系統消息隊列。可使用這個Hook回放經過使用WH_JOURNALRECORD Hook記錄下來的連續的鼠標和鍵盤事件。只要WH_JOURNALPLAYBACK Hook已經安裝,正常的鼠標和鍵盤事件就是無效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象線程特定Hook同樣使用。WH_JOURNALPLAYBACK Hook返回超時值,這個值告訴系統在處理來自回放Hook當前消息以前須要等待多長時間(毫秒)。這就使Hook能夠控制實時事件的回放。WH_JOURNALPLAYBACK是system-wide local hooks,它們不會被注射到任何行程位址空間。(估計按鍵精靈是用這個hook作的)七、WH_JOURNALRECORD HookWH_JOURNALRECORD Hook用來監視和記錄輸入事件。典型的,可使用這個Hook記錄連續的鼠標和鍵盤事件,而後經過使用WH_JOURNALPLAYBACK Hook來回放。WH_JOURNALRECORD Hook是全局Hook,它不能象線程特定Hook同樣使用。WH_JOURNALRECORD是system-wide local hooks,它們不會被注射到任何行程位址空間。八、WH_KEYBOARD Hook在應用程序中,WH_KEYBOARD Hook用來監視WM_KEYDOWN and WM_KEYUP消息,這些消息經過GetMessage or PeekMessage function返回。可使用這個Hook來監視輸入到消息隊列中的鍵盤消息。九、WH_KEYBOARD_LL HookWH_KEYBOARD_LL Hook監視輸入到線程消息隊列中的鍵盤消息。十、WH_MOUSE HookWH_MOUSE Hook監視從GetMessage 或者 PeekMessage 函數返回的鼠標消息。使用這個Hook監視輸入到消息隊列中的鼠標消息。十一、WH_MOUSE_LL HookWH_MOUSE_LL Hook監視輸入到線程消息隊列中的鼠標消息。十二、WH_MSGFILTER 和 WH_SYSMSGFILTER HooksWH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱們能夠監視菜單,滾動條,消息框,對話框消息而且發現用戶使用ALT+TAB or ALT+ESC 組合鍵切換窗口。WH_MSGFILTER Hook只能監視傳遞到菜單,滾動條,消息框的消息,以及傳遞到經過安裝了Hook子程的應用程序創建的對話框的消息。WH_SYSMSGFILTER Hook監視全部應用程序消息。WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱們能夠在模式循環期間過濾消息,這等價於在主消息循環中過濾消息。經過調用CallMsgFilter function能夠直接的調用WH_MSGFILTER Hook。經過使用這個函數,應用程序可以在模式循環期間使用相同的代碼去過濾消息,如同在主消息循環裏同樣。1三、WH_SHELL Hook外殼應用程序可使用WH_SHELL Hook去接收重要的通知。當外殼應用程序是激活的而且當頂層窗口創建或者銷燬時,系統調用WH_SHELL Hook子程。WH_SHELL 共有5鍾情況:    1. 只要有個top-level、unowned 窗口被產生、起做用、或是被摧毀;    2. 當Taskbar須要重畫某個按鈕;    3. 當系統須要顯示關於Taskbar的一個程序的最小化形式;    4. 當目前的鍵盤佈局狀態改變;    5. 當使用者按Ctrl+Esc去執行Task Manager(或相同級別的程序)。按照慣例,外殼應用程序都不接收WH_SHELL消息。因此,在應用程序可以接收WH_SHELL消息以前,應用程序必須調用SystemParametersInfo function註冊它本身。

相關文章
相關標籤/搜索