十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
怎样在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...”,这可怎么办呢?

别担心,办法总是有的,经过一番摸索以后,发现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中的定义
- ///WindowsNT/2000/XP:
 
Installsahookprocedurethatmonitorslow-levelmouseinputevents.- ///[Page]
 - privateconstintWH_MOUSE_LL=14;
 - /**////
 - ///WindowsNT/2000/XP:
 
Installsahookprocedurethatmonitorslow-levelkeyboardinputevents.- ///
 - 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;
 - }
 
【编辑推荐】