C#實現全局鉤子步驟
怎樣在C#中使用全局鉤子?以前寫的全局鉤子都是用unmanaged C或C++寫個DLL來實現,可大家都知道,C#是基于.Net Framework的,是managed,怎么讓C#實現全局鉤子呢?于是開始到網上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面詳細的說明了如何使用鼠標鉤子捕獲鼠標的移動等,可是,它只能在Application里起作用,出了Application就沒用了,就是說它還是沒有實現全局鉤子,而且文章結尾處說:“Global Hooks are not supported in the .NET Framework...”,這可怎么辦呢?
別擔心,辦法總是有的,經過一番摸索以后,發(fā)現WH_KEYBORAD_LL和WH_MOUSE_LL這兩個low-level的hook可以被安裝成全局的,這就好辦了,我們不妨用這兩個low-level的hook替換掉WH_KEYBORAD和WH_MOUSE,于是開始測試。結果成功了,在C#實現全局鉤子。
我們來看一下主要代碼段。
首先倒入所需要的windows函數,主要有三個,SetWindowsHookEX用來安裝鉤子,UnhookWindowsHookEX用來卸載鉤子以及CallNextHookEX用來將hook信息傳遞到鏈表中下一個hook處理過程。
- [DllImport(\"user32.dll\",CharSetCharSet=CharSet.Auto,
- CallingConventionCallingConvention=CallingConvention.StdCall,SetLastError=true)]
- privatestaticexternintSetWindowsHookEx(
- intidHook,
- HookProclpfn,
- IntPtrhMod,
- intdwThreadId);
- [DllImport(\"user32.dll\",CharSetCharSet=CharSet.Auto,
- CallingConventionCallingConvention=CallingConvention.StdCall,SetLastError=true)]
- privatestaticexternintUnhookWindowsHookEx(intidHook);
- [DllImport(\"user32.dll\",CharSetCharSet=CharSet.Auto,
- CallingConventionCallingConvention=CallingConvention.StdCall)]
- privatestaticexternintCallNextHookEx(
- intidHook,
- intnCode,
- intwParam,
- IntPtrlParam);
有關這兩個low-level hook在Winuser.h中的定義
- <summary>
- ///WindowsNT/2000/XP:
Installsahookprocedurethatmonitorslow-levelmouseinputevents.- ///</summary>[Page]
- privateconstintWH_MOUSE_LL=14;
- /**////<summary>
- ///WindowsNT/2000/XP:
Installsahookprocedurethatmonitorslow-levelkeyboardinputevents.- ///</summary>
- privateconstintWH_KEYBOARD_LL=13;
在安裝全局鉤子的時候,我們就要做替換了,將WH_MOUSE和WH_KEYBORAD分別換成WH_MOUSE_LL和WH_KEYBORAD_LL:
- //installhook
- hMouseHook=SetWindowsHookEx(
- WH_MOUSE_LL, //原來是WH_MOUSE
- MouseHookProcedure,
- Marshal.GetHINSTANCE(
- Assembly.GetExecutingAssembly().GetModules()[0]),
- 0);
- //installhook
- hKeyboardHook=SetWindowsHookEx(
- WH_KEYBOARD_LL,//原來是WH_KEYBORAD
- KeyboardHookProcedure,
- Marshal.GetHINSTANCE(
- Assembly.GetExecutingAssembly().GetModules()[0]),
- 0);[Page]
這樣替換了之后,我們就可以C#實現全局鉤子了,而且,不需要寫DLL。看一下程序運行情況:
下面是關于鼠標和鍵盤的兩個Callback函數:
- private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
- {
- // if ok and someone listens to our events
- if ((nCode >= 0) && (OnMouseActivity != null))
- {
- //Marshall the data from callback.
- MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.
PtrToStructure(lParam, typeof(MouseLLHookStruct));- //detect button clicked
- MouseButtons button = MouseButtons.None;
- short mouseDelta = 0;
- switch (wParam)
- {
- case WM_LBUTTONDOWN:
- //case WM_LBUTTONUP:
- //case WM_LBUTTONDBLCLK:
- button = MouseButtons.Left;
- break; [Page]
- case WM_RBUTTONDOWN:
- //case WM_RBUTTONUP:
- //case WM_RBUTTONDBLCLK:
- button = MouseButtons.Right;
- break;
- case WM_MOUSEWHEEL:
- //If the message is WM_MOUSEWHEEL,
the high-order word of mouseData member is the wheel delta.- //One wheel click is defined as WHEEL_DELTA, which is 120.
- //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
- mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
- //TODO: X BUTTONS (I havent them so was unable to test)
- //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP,
WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,[Page]- //or WM_NCXBUTTONDBLCLK,
the high-order word specifies which X button was pressed or released,- //and the low-order word is reserved.
This value can be one or more of the following values.- //Otherwise, mouseData is not used.
- break;
- }
【編輯推薦】