首页 > Windows开发 > 详细

C# 鼠标和键盘Hook

时间:2016-03-20 16:11:44      阅读:407      评论:0      收藏:0      [点我收藏+]

  Hook是一种拦截特定类型消息的方法,例如注册一个全局鼠标Hook,就可以在事件发生前截取到这个消息。

  Windows 中的Hook大概分为……这么多吧。

  技术分享

  虽说C#是托管语言,不可以通过本身的类库和方法去创建钩子的,但是调用非托管类库还是没有问题的。要使用的钩子为Object Hook,我们可以使用DllImport引用非托管类库中的方法。安装钩子的方法(SetWindowsHookEx)的类库在user32.dll文件中,函数的原型如下:

1 HHOOK WINAPI SetWindowsHookEx(
2   _In_ int       idHook,
3   _In_ HOOKPROC  lpfn,
4   _In_ HINSTANCE hInstance,
5   _In_ DWORD     dwThreadId
6 );

  返回值为钩子的句柄,这个句柄很重要,卸载钩子时要用。在C#中应这样声明:

1 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
2 private static extern IntPtr SetWindowsHookEx(
3     int idHook,        //钩子的类型
4     HookProc lpfn,     //引发钩子时的回调函数
5     IntPtr hInstance,  //应用程序的实例句柄
6     int dwThreadId);   //要监听的线程的ID

   有安装也当然有卸载,原型为: 

1 BOOL WINAPI UnhookWindowsHookEx(
2    _In_ HHOOK hhk
3 );

    C#中声明: 

1 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
2 private static extern bool UnhookWindowsHookEx(
3     IntPtr idHook);    //要卸载钩子的句柄

   SetWindowsHookEx第一个参数为钩子类型,一共有15种钩子,这里只给出鼠标和键盘钩子:

1 /// <summary>
2 /// 监视输入到线程消息队列中的键盘消息
3 /// </summary>
4 int WH_KEYBOARD_ALL = 13,
5 
6 /// <summary>
7 /// 监视输入到线程消息队列中的鼠标消息
8 /// </summary>
9 int WH_MOUSE_ALL = 14

  SetWindowsHookEx还有一个回调函数HookProc,需要我们去声明: 

1 private delegate int HookProc(int nCode, int wParam, IntPtr lParam);

   回调函数中的nCode表示前端钩子(可以安装多个钩子,但一般不这样做,因为很耗性能,除非你是搞破坏的)传回来的参数,0表示消息被废弃,非0表示消息仍然有效。wParam表示消息类型,一共有N多种消息,这里就不一一列举了,自己看代码。lParam返回消息结构的句柄,通过Marshal.PtrToStructure方法获得消息句柄,键盘和鼠标消息结构分别为:

 1 /// <summary>
 2 /// 键盘消息结构
 3 /// </summary>
 4 [StructLayout(LayoutKind.Sequential)]
 5 public class KeyboardHookStruct
 6 {
 7     /// <summary>
 8     /// 定一个虚拟键码。该代码必须有一个价值的范围1至254
 9     /// </summary>
10     public int vkCode;
11     /// <summary>
12     /// 指定的硬件扫描码
13     /// </summary>
14     public int scanCode;
15     /// <summary>
16     /// 键标志
17     /// </summary>
18     public int flags;
19     /// <summary>
20     /// 消息时间戳间
21     /// </summary>
22     public int time;
23     /// <summary>
24     /// 指定额外信息相关的信息
25     /// </summary>
26    public int dwExtraInfo;
27 }
28 
29 /// <summary>
30 /// 鼠标消息结构
31 /// </summary>
32 [StructLayout(LayoutKind.Sequential)]
33 public class MouseHookStruct
34 {
35     /// <summary>
36     /// POINT结构对象,保存鼠标在屏幕上的x,y坐标
37     /// </summary>
38     public Point pt;
39     /// <summary>
40     /// 接收到鼠标消息的窗口的句柄
41     /// </summary>
42     public IntPtr hWnd;
43     /// <summary>
44     /// hit-test值,详细描述参见WM_NCHITTEST消息
45     /// </summary>
46     public int wHitTestCode;
47     /// <summary>
48     /// 指定与本消息联系的额外消息
49     /// </summary>
50     public int dwExtraInfo;
51 }

  SetWindowsHookEx为应用程序的实例句柄,所以得再声明一个API函数:

1 [DllImport("kernel32.dll")]
2 private static extern IntPtr GetModuleHandle(
3     string name);    //要获取句柄的线程的名字

   万事俱备,仅需要两个安装钩子和两个卸载钩子的函数。

 1 /// <summary>
 2 /// 安装键盘钩子
 3 /// </summary>
 4 private void InsertKeyBoardHook()
 5 {
 6     if (KeyBoardHookPtr == IntPtr.Zero)
 7     {
 8         KeyboardHookProcedure = new HookProc(KeyboardHookProc);
 9         KeyBoardHookPtr = SetWindowsHookEx((int)HookType.WH_KEYBOARD_ALL, KeyboardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0); //使用全局钩子时,线程号为0
10         if (KeyBoardHookPtr == IntPtr.Zero) throw new Exception("安装钩子失败!");
11     }
12 }
13 
14 /// <summary>
15 /// 卸载键盘钩子
16 /// </summary>
17 private void DeleteKeyBoardHook()
18 {
19     if (KeyBoardHookPtr == IntPtr.Zero) return;
20     if (!UnhookWindowsHookEx(KeyBoardHookPtr)) throw new Exception("卸载钩子失败!");
21     KeyBoardHookPtr = IntPtr.Zero;
22 }
23 
24 
25 /// <summary>
26 /// 安装鼠标钩子
27 /// </summary>
28 private void InsertMouseHook()
29 {
30     if (MouseHookPtr == IntPtr.Zero)
31         {
32             MouseHookProcedure = new HookProc(MouseHookProc);
33             MouseHookPtr = SetWindowsHookEx((int)HookType.WH_MOUSE_ALL, MouseHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0); //使用全局钩子时,线程号为0
34             if (MouseHookPtr == IntPtr.Zero) throw new Exception("安装钩子失败!");
35     }
36 }
37 
38 /// <summary>
39 /// 卸载鼠标钩子
40 /// </summary>
41 private void DeleteMouseHook()
42 {
43     if (MouseHookPtr == IntPtr.Zero) return;
44     if (!UnhookWindowsHookEx(MouseHookPtr)) throw new Exception("卸载钩子失败!");
45     MouseHookPtr = IntPtr.Zero;
46 }

  这里给两个回掉函数例子:

  键盘钩子的回调函数,当按下数字键(数字键盘)就弹出提示框:   

 1 private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam)
 2 {
 3   if ((nCode >= 0) && (wParam == (int)MsgType.WM_KEYDOWN))
 4   {
 5     KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
 6     switch ((Keys)MyKeyboardHookStruct.vkCode)
 7     {
 8       case Keys.NumPad0:
 9       case Keys.NumPad1:
10       case Keys.NumPad2:
11       case Keys.NumPad3:
12       case Keys.NumPad4:
13       case Keys.NumPad5:
14       case Keys.NumPad6:
15       case Keys.NumPad7:
16       case Keys.NumPad8:
17       case Keys.NumPad9:
18 
19        System.Windows.MessageBox.Show("你按下了数字键"); break;
20     }
21   }
22   return 0; //0为废弃消息,非0为继续传递消息
23 }

    鼠标钩子的回调函数,当按下右键就弹出提示框,并显明按下时的位置: 

1 private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
2 {
3   if ((nCode >= 0) && (wParam == (int)MsgType.WM_RBUTTONDOWN))
4   {
5     MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
6     label1.Content = "你按下了鼠标右键,位置在:x " + MyMouseHookStruct.pt.X + " y " + MyMouseHookStruct.pt.Y;  //label1为一个label控件
7   }
8   return 0;
9 }

   代码下载  密码为:sy4u

C# 鼠标和键盘Hook

原文:http://www.cnblogs.com/Bita/p/5268522.html

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