首页 > 其他 > 详细

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

时间:2014-04-23 14:30:52      阅读:706      评论:0      收藏:0      [点我收藏+]

 今天,有个同事问我,怎样在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处理过程。

bubuko.com,布布扣[DllImport("user32.dll", CharSet = CharSet.Auto,
bubuko.com,布布扣           CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
bubuko.com,布布扣        
private static extern int SetWindowsHookEx(
bubuko.com,布布扣            
int idHook,
bubuko.com,布布扣            HookProc lpfn,
bubuko.com,布布扣            IntPtr hMod,
bubuko.com,布布扣            
int dwThreadId);
bubuko.com,布布扣
bubuko.com,布布扣[DllImport(
"user32.dll", CharSet = CharSet.Auto,
bubuko.com,布布扣            CallingConvention 
= CallingConvention.StdCall, SetLastError = true)]
bubuko.com,布布扣        
private static extern int UnhookWindowsHookEx(int idHook);
bubuko.com,布布扣
bubuko.com,布布扣[DllImport(
"user32.dll", CharSet = CharSet.Auto,
bubuko.com,布布扣             CallingConvention 
= CallingConvention.StdCall)]
bubuko.com,布布扣        
private static extern int CallNextHookEx(
bubuko.com,布布扣            
int idHook,
bubuko.com,布布扣            
int nCode,
bubuko.com,布布扣            
int wParam,
bubuko.com,布布扣            IntPtr lParam);

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

bubuko.com,布布扣/// <summary>
bubuko.com,布布扣        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
bubuko.com,布布扣        
/// </summary> 

bubuko.com,布布扣        private const int WH_MOUSE_LL       = 14;
bubuko.com,布布扣        
/// <summary>
bubuko.com,布布扣        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
bubuko.com,布布扣        
/// </summary> 

bubuko.com,布布扣        private const int WH_KEYBOARD_LL    = 13;

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

bubuko.com,布布扣//install hook
bubuko.com,布布扣
                hMouseHook = SetWindowsHookEx(
bubuko.com,布布扣                    WH_MOUSE_LL, 
//原来是WH_MOUSE
bubuko.com,布布扣
                    MouseHookProcedure,
bubuko.com,布布扣                    Marshal.GetHINSTANCE(
bubuko.com,布布扣                        Assembly.GetExecutingAssembly().GetModules()[
0]),
bubuko.com,布布扣                    
0);
bubuko.com,布布扣
bubuko.com,布布扣
//install hook
bubuko.com,布布扣
                hKeyboardHook = SetWindowsHookEx(
bubuko.com,布布扣                    WH_KEYBOARD_LL, 
//原来是WH_KEYBORAD
bubuko.com,布布扣
                    KeyboardHookProcedure,
bubuko.com,布布扣                    Marshal.GetHINSTANCE(
bubuko.com,布布扣                    Assembly.GetExecutingAssembly().GetModules()[
0]),
bubuko.com,布布扣                    
0);
 
  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:

bubuko.com,布布扣

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

bubuko.com,布布扣private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
bubuko.com,布布扣        
{
bubuko.com,布布扣            
// if ok and someone listens to our events
bubuko.com,布布扣
            if ((nCode >= 0&& (OnMouseActivity != null))
bubuko.com,布布扣            
{
bubuko.com,布布扣                
//Marshall the data from callback.
bubuko.com,布布扣
                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
bubuko.com,布布扣
bubuko.com,布布扣                
//detect button clicked
bubuko.com,布布扣
                MouseButtons button = MouseButtons.None;
bubuko.com,布布扣                
short mouseDelta = 0;
bubuko.com,布布扣                
switch (wParam)
bubuko.com,布布扣                
{
bubuko.com,布布扣                    
case WM_LBUTTONDOWN:
bubuko.com,布布扣                        
//case WM_LBUTTONUP: 
bubuko.com,布布扣                        
//case WM_LBUTTONDBLCLK: 
bubuko.com,布布扣
                        button = MouseButtons.Left;
bubuko.com,布布扣                        
break;
bubuko.com,布布扣                    
case WM_RBUTTONDOWN:
bubuko.com,布布扣                        
//case WM_RBUTTONUP: 
bubuko.com,布布扣                        
//case WM_RBUTTONDBLCLK: 
bubuko.com,布布扣
                        button = MouseButtons.Right;
bubuko.com,布布扣                        
break;
bubuko.com,布布扣                    
case WM_MOUSEWHEEL:
bubuko.com,布布扣                        
//If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 
bubuko.com,布布扣                        
//One wheel click is defined as WHEEL_DELTA, which is 120. 
bubuko.com,布布扣                        
//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
bubuko.com,布布扣
                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16& 0xffff);
bubuko.com,布布扣                        
//TODO: X BUTTONS (I havent them so was unable to test)
bubuko.com,布布扣                        
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 
bubuko.com,布布扣                        
//or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
bubuko.com,布布扣                        
//and the low-order word is reserved. This value can be one or more of the following values. 
bubuko.com,布布扣                        
//Otherwise, mouseData is not used. 
bubuko.com,布布扣
                        break;
bubuko.com,布布扣                }

bubuko.com,布布扣
bubuko.com,布布扣                
//double clicks
bubuko.com,布布扣
                int clickCount = 0;
bubuko.com,布布扣                
if (button != MouseButtons.None)
bubuko.com,布布扣                    
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
bubuko.com,布布扣                    
else clickCount = 1;
bubuko.com,布布扣
bubuko.com,布布扣                
//generate event 
bubuko.com,布布扣
                 MouseEventArgs e = new MouseEventArgs(
bubuko.com,布布扣                                                    button,
bubuko.com,布布扣                                                    clickCount,
bubuko.com,布布扣                                                    mouseHookStruct.pt.x,
bubuko.com,布布扣                                                    mouseHookStruct.pt.y,
bubuko.com,布布扣                                                    mouseDelta);
bubuko.com,布布扣                
//raise it
bubuko.com,布布扣
                OnMouseActivity(this, e);
bubuko.com,布布扣            }

bubuko.com,布布扣            
//call next hook
bubuko.com,布布扣
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
bubuko.com,布布扣        }

bubuko.com,布布扣
 
bubuko.com,布布扣private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
bubuko.com,布布扣        
{
bubuko.com,布布扣            
//indicates if any of underlaing events set e.Handled flag
bubuko.com,布布扣
            bool handled = false;
bubuko.com,布布扣            
//it was ok and someone listens to events
bubuko.com,布布扣
            if ((nCode >= 0&& (KeyDown != null || KeyUp != null || KeyPress != null))
bubuko.com,布布扣            
{
bubuko.com,布布扣                
//read structure KeyboardHookStruct at lParam
bubuko.com,布布扣
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
bubuko.com,布布扣                
//raise KeyDown
bubuko.com,布布扣
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
bubuko.com,布布扣                
{
bubuko.com,布布扣                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
bubuko.com,布布扣                    KeyEventArgs e 
= new KeyEventArgs(keyData);
bubuko.com,布布扣                    KeyDown(
this, e);
bubuko.com,布布扣                    handled 
= handled || e.Handled;
bubuko.com,布布扣                }

bubuko.com,布布扣
bubuko.com,布布扣                
// raise KeyPress
bubuko.com,布布扣
                if (KeyPress != null && wParam == WM_KEYDOWN)
bubuko.com,布布扣                
{
bubuko.com,布布扣                    
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80== 0x80 ? true : false);
bubuko.com,布布扣                    
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
bubuko.com,布布扣
bubuko.com,布布扣                    
byte[] keyState = new byte[256];
bubuko.com,布布扣                    GetKeyboardState(keyState);
bubuko.com,布布扣                    
byte[] inBuffer = new byte[2];
bubuko.com,布布扣                    
if (ToAscii(MyKeyboardHookStruct.vkCode,
bubuko.com,布布扣                              MyKeyboardHookStruct.scanCode,
bubuko.com,布布扣                              keyState,
bubuko.com,布布扣                              inBuffer,
bubuko.com,布布扣                              MyKeyboardHookStruct.flags) 
== 1)
bubuko.com,布布扣                    
{
bubuko.com,布布扣                        
char key = (char)inBuffer[0];
bubuko.com,布布扣                        
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
bubuko.com,布布扣                        KeyPressEventArgs e 
= new KeyPressEventArgs(key);
bubuko.com,布布扣                        KeyPress(
this, e);
bubuko.com,布布扣                        handled 
= handled || e.Handled;
bubuko.com,布布扣                    }

bubuko.com,布布扣                }

bubuko.com,布布扣
bubuko.com,布布扣                
// raise KeyUp
bubuko.com,布布扣
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
bubuko.com,布布扣                
{
bubuko.com,布布扣                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
bubuko.com,布布扣                    KeyEventArgs e 
= new KeyEventArgs(keyData);
bubuko.com,布布扣                    KeyUp(
this, e);
bubuko.com,布布扣                    handled 
= handled || e.Handled;
bubuko.com,布布扣                }

bubuko.com,布布扣
bubuko.com,布布扣            }

bubuko.com,布布扣
bubuko.com,布布扣            
//if event handled in application do not handoff to other listeners
bubuko.com,布布扣
            if (handled)
bubuko.com,布布扣                
return 1;
bubuko.com,布布扣            
else
bubuko.com,布布扣                
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
bubuko.com,布布扣        }

如何在C#中使用全局鼠标、键盘Hook,布布扣,bubuko.com

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

原文:http://www.cnblogs.com/MaxWoods/p/3681791.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!