今天,有个同事问我,怎样在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...”,这可怎么办呢?class="Apple-converted-space"> 发现 WH_KEY BORA D_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。  卸载 钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。      
C#代码
 javascripts/syntaxhighlighter/clipboard_new.swf" type="application/x-shockwave-flash">can %20be%20one%20or%20more%20of%20the%20following%20values.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FOtherwise%2C%20mouseData%20is%20not%20used.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fdouble%20clicks%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20clickCount%20%3D%200%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(button%20!%3D%20MouseButtons.None)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(wParam%20%3D%3D%20WM_LBUTTONDBLCLK%20%7C%7C%20wParam%20%3D%3D%20WM_RBUTTONDBLCLK)%20clickCount%20%3D%202%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20clickCount%20%3D%201%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fgenerate%20event%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20MouseEventArgs%20e%20%3D%20new%20MouseEventArgs(%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20button%2C%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20clickCount%2C%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mouseHookStruct.pt.x%2C%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mouseHookStruct.pt.y%2C%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mouseDelta)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fraise%20it%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20OnMouseActivity(this%2C%20e)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fcall%20next%20hook%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20CallNextHookEx(hMouseHook%2C%20nCode%2C%20wParam%2C%20lParam)%3B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%0A%0Aprivate%20int%20KeyboardHookProc(int%20nCode%2C%20Int32%20wParam%2C%20IntPtr%20lParam)%0A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Findicates%20if%20any%20of%20underlaing%20events%20set%20e.Handled%20flag%0A%20%20%20%20%20%20%20%20%20%20%20%20bool%20handled%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fit%20was%20ok%20and%20someone%20listens%20to%20events%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20((nCode%20%3E%3D%200)%20%26%26%20(KeyDown%20!%3D%20null%20%7C%7C%20KeyUp%20!%3D%20null%20%7C%7C%20KeyPress%20!%3D%20null))%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fread%20structure%20KeyboardHookStruct%20at%20lParam%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyboardHookStruct%20MyKeyboardHookStruct%20%3D%20(KeyboardHookStruct)Marshal.PtrToStructure(lParam%2C%20typeof(KeyboardHookStruct))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fraise%20KeyDown%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(KeyDown%20!%3D%20null%20%26%26%20(wParam%20%3D%3D%20WM_KEYDOWN%20%7C%7C%20wParam%20%3D%3D%20WM_SYSKEYDOWN))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Keys%20keyData%20%3D%20(Keys)MyKeyboardHookStruct.vkCode%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyEventArgs%20e%20%3D%20new%20KeyEventArgs(keyData)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyDown(this%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20handled%20%3D%20handled%20%7C%7C%20e.Handled%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20raise%20KeyPress%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(KeyPress%20!%3D%20null%20%26%26%20wParam%20%3D%3D%20WM_KEYDOWN)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bool%20isDownShift%20%3D%20((GetKeyState(VK_SHIFT)%20%26%200x80)%20%3D%3D%200x80%20%3F%20true%20%3A%20false)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bool%20isDownCapslock%20%3D%20(GetKeyState(VK_CAPITAL)%20!%3D%200%20%3F%20true%20%3A%20false)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20byte%5B%5D%20keyState%20%3D%20new%20byte%5B256%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20GetKeyboardState(keyState)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20byte%5B%5D%20inBuffer%20%3D%20new%20byte%5B2%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(ToAscii(MyKeyboardHookStruct.vkCode%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20MyKeyboardHookStruct.scanCode%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyState%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inBuffer%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20MyKeyboardHookStruct.flags)%20%3D%3D%201)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20char%20key%20%3D%20(char)inBuffer%5B0%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20((isDownCapslock%20%5E%20isDownShift)%20%26%26%20Char.IsLetter(key))%20key%20%3D%20Char.ToUpper(key)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyPressEventArgs%20e%20%3D%20new%20KeyPressEventArgs(key)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyPress(this%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20handled%20%3D%20handled%20%7C%7C%20e.Handled%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20raise%20KeyUp%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(KeyUp%20!%3D%20null%20%26%26%20(wParam%20%3D%3D%20WM_KEYUP%20%7C%7C%20wParam%20%3D%3D%20WM_SYSKEYUP))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Keys%20keyData%20%3D%20(Keys)MyKeyboardHookStruct.vkCode%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyEventArgs%20e%20%3D%20new%20KeyEventArgs(keyData)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20KeyUp(this%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20handled%20%3D%20handled%20%7C%7C%20e.Handled%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fif%20event%20handled%20in%20application%20do%20not%20handoff%20to%20other%20listeners%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(handled)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20CallNextHookEx(hKeyboardHook%2C%20nCode%2C%20wParam%2C%20lParam)%3B%0A%20%20%20%20%20%20%20%20%7D" />   
[DllImport("user32.dll", CharSet = CharSet.Auto,    
           CallingConvention = CallingConvention.StdCall, SetLastError = true)]    
        private static extern int SetWindowsHookEx(       
            int idHook,    
            HookProc lpfn,   
            IntPtr hMod,   
            int dwThreadId);    
   
[DllImport("user32.dll", CharSet = CharSet.Auto,    
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]    
        private static extern int UnhookWindowsHookEx(int idHook);        
   
[DllImport("user32.dll", CharSet = CharSet.Auto,    
             CallingConvention = CallingConvention.StdCall)]   
        private static extern int CallNextHookEx(       
            int idHook,    
            int nCode,    
            int wParam,    
            IntPtr lParam);   
   
  下面是有关这两个low-level hook在Winuser.h中的定义:   
   
   
         
         
        private const int WH_MOUSE_LL       = 14;      
         
         
         
        private const int WH_KEYBOARD_LL    = 13;      
   
  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:   
   
   
                hMouseHook = SetWindowsHookEx(   
                    WH_MOUSE_LL,  
                    MouseHookProcedure,   
                    Marshal.GetHINSTANCE(   
                        Assembly.GetExecutingAssembly().GetModules()[0]),   
                    0);   
   
                hKeyboardHook = SetWindowsHookEx(   
                    WH_KEYBOARD_LL,  
                    KeyboardHookProcedure,   
                    Marshal.GetHINSTANCE(   
                    Assembly.GetExecutingAssembly().GetModules()[0]),   
                    0);   
   
  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:   
   
   
   
  下面是关于鼠标和键盘的两个Callback函数:   
   
   
private int MouseHookProc(int nCode, int wParam, IntPtr lParam)         
        {   
   
             
   
            if ((nCode >= 0) && (OnMouseActivity != null))     
   
            {   
   
                 
   
                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));    
   
   
                 
   
                MouseButtons button = MouseButtons.None;   
   
                short mouseDelta = 0;    
   
                switch (wParam)    
   
                {   
   
                    case WM_LBUTTONDOWN:    
   
                         
   
                         
   
                        button = MouseButtons.Left;   
   
                        break;    
   
                    case WM_RBUTTONDOWN:    
   
                         
   
                         
   
                        button = MouseButtons.Right;   
   
                        break;    
   
                    case WM_MOUSEWHEEL:    
   
                         
   
                         
   
                         
   
                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);    
   
                         
   
                         
   
                         
   
                         
   
                         
   
                        break;    
   
                }   
   
   
                 
   
                int clickCount = 0;    
   
                if (button != MouseButtons.None)    
   
                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;    
   
                    else clickCount = 1;    
   
   
                 
   
                 MouseEventArgs e = new MouseEventArgs(    
   
                                                    button,   
   
                                                    clickCount,   
   
                                                    mouseHookStruct.pt.x,   
   
                                                    mouseHookStruct.pt.y,   
   
                                                    mouseDelta);   
   
                 
   
                OnMouseActivity(this, e);    
   
            }   
   
             
   
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);    
   
        }   
   
   
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)     {   
             
            bool handled = false;     
             
            if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))       
            {   
                 
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));    
                 
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))     
                {   
                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;   
                    KeyEventArgs e = new KeyEventArgs(keyData);    
                    KeyDown(this, e);    
                    handled = handled || e.Handled;   
                }   
   
                 
                if (KeyPress != null && wParam == WM_KEYDOWN)     
                {   
                    bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);      
                    bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);      
   
                    byte[] keyState = new byte[256];      
                    GetKeyboardState(keyState);   
                    byte[] inBuffer = new byte[2];      
                    if (ToAscii(MyKeyboardHookStruct.vkCode,    
                              MyKeyboardHookStruct.scanCode,   
                              keyState,   
                              inBuffer,   
                              MyKeyboardHookStruct.flags) == 1)   
                    {   
                        char key = (char)inBuffer[0];     
                        if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);    
                        KeyPressEventArgs e = new KeyPressEventArgs(key);    
                        KeyPress(this, e);    
                        handled = handled || e.Handled;   
                    }   
                }   
   
                 
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))     
                {   
                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;   
                    KeyEventArgs e = new KeyEventArgs(keyData);    
                    KeyUp(this, e);    
                    handled = handled || e.Handled;   
                }   
   
            }   
   
             
            if (handled)    
                return 1;    
            else    
                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);    
        }