[C#] Easy Hook Library

來源:互聯網
上載者:User
簡介.NET似乎都沒有比較好用的Hook類庫,那就只好自己來做一個。

設計概念

原先我只是想將Hook的API做一些簡單的封裝,將其封裝成一個Hook類,做一做發現其實Hook其實也不多,那乾脆先用enum將所有的hook type(參考:http://msdn.microsoft.com/en-us/library/ms644959%28v=vs.85%29.aspx)一併聲明好了

因此我利用Dictionary資料結構,Key為自定的HookType,Value為自行封裝的Hook類,並用一個HookManager來管理Dictionary,對Hook做Register跟Unregister的動作。

同時在register時提供自訂的delegate,以實踐自訂的hookproc。

public enum HookType{    WH_MSGFILTER = -1,    WH_JOURNALRECORD = 0,    WH_JOURNALPLAYBACK = 1,    WH_KEYBOARD = 2,    WH_GETMESSAGE = 3,    WH_CALLWNDPROC = 4,    WH_CBT = 5,    WH_SYSMSGFILTER = 6,    WH_MOUSE = 7,    WH_DEBUG = 9,    WH_SHELL = 10,    WH_FOREGROUNDIDLE = 11,    WH_CALLWNDPROCRET = 12,    WH_KEYBOARD_LL = 13,    WH_MOUSE_LL = 14}

關於HookType中的WH_XXXX數值,請參照WinUser.h中的聲明。

class _HookProc{    #region "Declare API for Hook"    [DllImport("user32.dll", CharSet = CharSet.Auto,    CallingConvention = CallingConvention.StdCall)]    static extern int SetWindowsHookEx(int idHook, _HookProcHandler lpfn,    IntPtr hInstance, int threadId);    [DllImport("user32.dll", CharSet = CharSet.Auto,    CallingConvention = CallingConvention.StdCall)]    static extern bool UnhookWindowsHookEx(int idHook);    [DllImport("user32.dll", CharSet = CharSet.Auto,    CallingConvention = CallingConvention.StdCall)]    static extern int CallNextHookEx(int idHook, int nCode,    IntPtr wParam, IntPtr lParam);    [DllImport("kernel32.dll")]    static extern int GetCurrentThreadId();    #endregion    #region "Hook Proc"    int MyHookProc(int nCode, IntPtr wParam, IntPtr lParam)    {        if (m_CustomHookProc != null)            m_CustomHookProc(nCode, wParam, lParam);        return CallNextHookEx(m_HookHandle, nCode, wParam, lParam);    }    #endregion    CustomHookProc.HookProcHandler m_CustomHookProc;    delegate int _HookProcHandler(int nCode, IntPtr wParam, IntPtr lParam);    _HookProcHandler m_KbdHookProc;    int m_HookHandle = 0;    public _HookProc(HookType a_eHookType, CustomHookProc.HookProcHandler a_pHookProc)    {        m_CustomHookProc = a_pHookProc;        m_KbdHookProc = new _HookProcHandler(MyHookProc);        m_HookHandle = SetWindowsHookEx((int)a_eHookType, m_KbdHookProc, IntPtr.Zero, GetCurrentThreadId());        if (m_HookHandle == 0)        {            throw new Exception(string.Format("Hook {0} to {1} Error:{2}", a_eHookType.ToString(), a_pHookProc.ToString(), Marshal.GetLastWin32Error()));        }    }    ~_HookProc()    {        UnhookWindowsHookEx(m_HookHandle);        Debug.WriteLine(Marshal.GetLastWin32Error());        m_HookHandle = 0;    }}

public class CustomHookProc{    private CustomHookProc(){}    public delegate void HookProcHandler(int nCode, IntPtr wParam, IntPtr lParam);}

前面的幾個API的聲明,是在.NET中呼叫Win32 API的方法(參考:http://msdn.microsoft.com/en-us/library/aa984739%28v=VS.71%29.aspx)。

重點是在MyHookProc,SetWindowsHookEx會將Hook指到這個函數,同時在這個函數執行時,會將Hook到的訊息丟到外部的CustomHookProc.HookProcHandler Delegate。

public class HookManager{    private HookManager(){}    static readonly HookManager m_instance = new HookManager();    Dictionary<HookType, _HookProc> m_hooks = new Dictionary<HookType, _HookProc>();    public static HookManager Instance    {        get { return m_instance; }    }    public void RegisterHook(HookType a_eHookType, CustomHookProc.HookProcHandler a_pHookProc)    {        if(!m_hooks.ContainsKey(a_eHookType))        {            m_hooks.Add(a_eHookType, new _HookProc(a_eHookType, a_pHookProc));        }        else        {            throw new Exception(string.Format("{0} already exist!", a_eHookType.ToString()));        }    }    public void Unregister(HookType a_eHookType)    {        m_hooks.Remove(a_eHookType);    }}

HookManager類是一個單例類,它負責維護所有的Hook。

private void Form1_Load(object sender, EventArgs e){    HookManager.Instance.RegisterHook(HookType.WH_KEYBOARD, new CustomHookProc.HookProcHandler(KeyboardHookProc));    HookManager.Instance.RegisterHook(HookType.WH_MOUSE, new CustomHookProc.HookProcHandler(MouseHookProc));}void KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam){    KeyStateInfo ctrlKey = KeyboardInfo.GetKeyState(Keys.ControlKey);    KeyStateInfo altKey = KeyboardInfo.GetKeyState(Keys.Alt);    KeyStateInfo shiftKey = KeyboardInfo.GetKeyState(Keys.ShiftKey);    KeyStateInfo f8Key = KeyboardInfo.GetKeyState(Keys.F8);    if (ctrlKey.IsPressed)    {        Console.WriteLine("Ctrl Pressed!");    }    if (altKey.IsPressed)    {        Console.WriteLine("Alt Pressed!");    }    if (shiftKey.IsPressed)    {        Console.WriteLine("Shift Pressed!");    }    if (f8Key.IsPressed)    {        Console.WriteLine("F8 Pressed!");    }}void MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){    MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));    if (nCode >= 0)    {        String strCaption = "x = " +        MyMouseHookStruct.pt.x.ToString("d") +        "  y = " +        MyMouseHookStruct.pt.y.ToString("d");        Form tempForm = Form.ActiveForm;        tempForm.Text = strCaption;    }}

封裝完畢後,使用起來就非常簡單

HookManager.Instance.RegisterHook(HookType.WH_KEYBOARD, new CustomHookProc.HookProcHandler(KeyboardHookProc));
HookManager.Instance.RegisterHook(HookType.WH_MOUSE, new CustomHookProc.HookProcHandler(MouseHookProc));

像這樣使用,而且在HookProc中也不需要去管return CallNextHookEx(m_HookHandle, nCode, wParam, lParam);

只需針對自己所要處理的Hook處理即可。


參考連結

http://msdn.microsoft.com/zh-cn/magazine/cc188966(en-us).aspx

範例檔下載

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.