今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,​​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#里实现了全局钩子。


  我们来看一下主要代码段。示例源码下载地址请访问我的网站:​​http://www.vczx.com/article/show.php?id=1672​


  首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。





如何在C#中使用全局鼠标、键盘Hook_.net[DllImport("user32.dll", CharSet = CharSet.Auto,

如何在C#中使用全局鼠标、键盘Hook_.net           CallingConvention = CallingConvention.StdCall, SetLastError = true)]

如何在C#中使用全局鼠标、键盘Hook_.net        private static extern int SetWindowsHookEx(

如何在C#中使用全局鼠标、键盘Hook_.net            int idHook,

如何在C#中使用全局鼠标、键盘Hook_.net            HookProc lpfn,

如何在C#中使用全局鼠标、键盘Hook_.net            IntPtr hMod,

如何在C#中使用全局鼠标、键盘Hook_.net            int dwThreadId);

如何在C#中使用全局鼠标、键盘Hook_.net

如何在C#中使用全局鼠标、键盘Hook_.net[DllImport("user32.dll", CharSet = CharSet.Auto,

如何在C#中使用全局鼠标、键盘Hook_.net            CallingConvention = CallingConvention.StdCall, SetLastError = true)]

如何在C#中使用全局鼠标、键盘Hook_.net        private static extern int UnhookWindowsHookEx(int idHook);

如何在C#中使用全局鼠标、键盘Hook_.net

如何在C#中使用全局鼠标、键盘Hook_.net[DllImport("user32.dll", CharSet = CharSet.Auto,

如何在C#中使用全局鼠标、键盘Hook_.net             CallingConvention = CallingConvention.StdCall)]

如何在C#中使用全局鼠标、键盘Hook_.net        private static extern int CallNextHookEx(

如何在C#中使用全局鼠标、键盘Hook_.net            int idHook,

如何在C#中使用全局鼠标、键盘Hook_.net            int nCode,

如何在C#中使用全局鼠标、键盘Hook_.net            int wParam,

如何在C#中使用全局鼠标、键盘Hook_.net            IntPtr lParam);


  下面是有关这两个low-level hook在Winuser.h中的定义:





如何在C#中使用全局鼠标、键盘Hook_源码下载_20/// <summary>

如何在C#中使用全局鼠标、键盘Hook_源码下载_21        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.

如何在C#中使用全局鼠标、键盘Hook_sed_22        /// </summary> 

如何在C#中使用全局鼠标、键盘Hook_.net        private const int WH_MOUSE_LL       = 14;

如何在C#中使用全局鼠标、键盘Hook_源码下载_20        /// <summary>

如何在C#中使用全局鼠标、键盘Hook_源码下载_21        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.

如何在C#中使用全局鼠标、键盘Hook_sed_22        /// </summary> 

如何在C#中使用全局鼠标、键盘Hook_.net        private const int WH_KEYBOARD_LL    = 13;


  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:





如何在C#中使用全局鼠标、键盘Hook_.net//install hook

如何在C#中使用全局鼠标、键盘Hook_.net                hMouseHook = SetWindowsHookEx(

如何在C#中使用全局鼠标、键盘Hook_.net                    WH_MOUSE_LL, //原来是WH_MOUSE

如何在C#中使用全局鼠标、键盘Hook_.net                    MouseHookProcedure,

如何在C#中使用全局鼠标、键盘Hook_.net                    Marshal.GetHINSTANCE(

如何在C#中使用全局鼠标、键盘Hook_.net                        Assembly.GetExecutingAssembly().GetModules()[0]),

如何在C#中使用全局鼠标、键盘Hook_.net                    0);

如何在C#中使用全局鼠标、键盘Hook_.net

如何在C#中使用全局鼠标、键盘Hook_.net//install hook

如何在C#中使用全局鼠标、键盘Hook_.net                hKeyboardHook = SetWindowsHookEx(

如何在C#中使用全局鼠标、键盘Hook_.net                    WH_KEYBOARD_LL, //原来是WH_KEYBORAD

如何在C#中使用全局鼠标、键盘Hook_.net                    KeyboardHookProcedure,

如何在C#中使用全局鼠标、键盘Hook_.net                    Marshal.GetHINSTANCE(

如何在C#中使用全局鼠标、键盘Hook_.net                    Assembly.GetExecutingAssembly().GetModules()[0]),

如何在C#中使用全局鼠标、键盘Hook_.net                    0);


 


  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:



如何在C#中使用全局鼠标、键盘Hook_c#_43


  下面是关于鼠标和键盘的两个Callback函数:





如何在C#中使用全局鼠标、键盘Hook_.netprivate int MouseHookProc(int nCode, int wParam, IntPtr lParam)

如何在C#中使用全局鼠标、键盘Hook_源码下载_20        {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            // if ok and someone listens to our events

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            if ((nCode >= 0) && (OnMouseActivity != null))

如何在C#中使用全局鼠标、键盘Hook_代码段_48            {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //Marshall the data from callback.

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //detect button clicked

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                MouseButtons button = MouseButtons.None;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                short mouseDelta = 0;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                switch (wParam)

如何在C#中使用全局鼠标、键盘Hook_代码段_48                {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    case WM_LBUTTONDOWN:

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //case WM_LBUTTONUP: 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //case WM_LBUTTONDBLCLK: 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        button = MouseButtons.Left;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        break;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    case WM_RBUTTONDOWN:

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //case WM_RBUTTONUP: 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //case WM_RBUTTONDBLCLK: 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        button = MouseButtons.Right;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        break;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    case WM_MOUSEWHEEL:

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //One wheel click is defined as WHEEL_DELTA, which is 120. 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //TODO: X BUTTONS (I havent them so was unable to test)

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //and the low-order word is reserved. This value can be one or more of the following values. 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        //Otherwise, mouseData is not used. 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        break;

如何在C#中使用全局鼠标、键盘Hook_代码段_78                }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //double clicks

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                int clickCount = 0;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                if (button != MouseButtons.None)

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    else clickCount = 1;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //generate event 

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                 MouseEventArgs e = new MouseEventArgs(

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                                                    button,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                                                    clickCount,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                                                    mouseHookStruct.pt.x,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                                                    mouseHookStruct.pt.y,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                                                    mouseDelta);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //raise it

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                OnMouseActivity(this, e);

如何在C#中使用全局鼠标、键盘Hook_代码段_78            }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            //call next hook

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);

如何在C#中使用全局鼠标、键盘Hook_sed_22        }

如何在C#中使用全局鼠标、键盘Hook_.net


 




如何在C#中使用全局鼠标、键盘Hook_.netprivate int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)

如何在C#中使用全局鼠标、键盘Hook_源码下载_20        {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            //indicates if any of underlaing events set e.Handled flag

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            bool handled = false;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            //it was ok and someone listens to events

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))

如何在C#中使用全局鼠标、键盘Hook_代码段_48            {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //read structure KeyboardHookStruct at lParam

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                //raise KeyDown

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))

如何在C#中使用全局鼠标、键盘Hook_代码段_48                {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    KeyEventArgs e = new KeyEventArgs(keyData);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    KeyDown(this, e);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    handled = handled || e.Handled;

如何在C#中使用全局鼠标、键盘Hook_代码段_78                }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                // raise KeyPress

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                if (KeyPress != null && wParam == WM_KEYDOWN)

如何在C#中使用全局鼠标、键盘Hook_代码段_48                {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    byte[] keyState = new byte[256];

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    GetKeyboardState(keyState);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    byte[] inBuffer = new byte[2];

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    if (ToAscii(MyKeyboardHookStruct.vkCode,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                              MyKeyboardHookStruct.scanCode,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                              keyState,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                              inBuffer,

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                              MyKeyboardHookStruct.flags) == 1)

如何在C#中使用全局鼠标、键盘Hook_代码段_48                    {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        char key = (char)inBuffer[0];

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        KeyPressEventArgs e = new KeyPressEventArgs(key);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        KeyPress(this, e);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                        handled = handled || e.Handled;

如何在C#中使用全局鼠标、键盘Hook_代码段_78                    }

如何在C#中使用全局鼠标、键盘Hook_代码段_78                }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                // raise KeyUp

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))

如何在C#中使用全局鼠标、键盘Hook_代码段_48                {

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    KeyEventArgs e = new KeyEventArgs(keyData);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    KeyUp(this, e);

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                    handled = handled || e.Handled;

如何在C#中使用全局鼠标、键盘Hook_代码段_78                }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_代码段_78            }

如何在C#中使用全局鼠标、键盘Hook_源码下载_21

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            //if event handled in application do not handoff to other listeners

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            if (handled)

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                return 1;

如何在C#中使用全局鼠标、键盘Hook_源码下载_21            else

如何在C#中使用全局鼠标、键盘Hook_源码下载_21                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);

如何在C#中使用全局鼠标、键盘Hook_sed_22        }