今天,有个同事问我,怎样在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#里实现了全局钩子。

  我们来看一下主要代码段。

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

    1. [DllImport("user32.dll", CharSet = CharSet.Auto,
    2. CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    3. private static extern int SetWindowsHookEx(
    4. int idHook,
    5. HookProc lpfn,
    6. IntPtr hMod,
    7. int dwThreadId);
    8. [DllImport("user32.dll", CharSet = CharSet.Auto,
    9. CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    10. private static extern int UnhookWindowsHookEx(int idHook);
    11. [DllImport("user32.dll", CharSet = CharSet.Auto,
    12. CallingConvention = CallingConvention.StdCall)]
    13. private static extern int CallNextHookEx(
    14. int idHook,
    15. int nCode,
    16. int wParam,
    17. IntPtr lParam);
    18.   下面是有关这两个low-level hook在Winuser.h中的定义:
    19. /// <summary>
    20. /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
    21. /// </summary>
    22. private const int WH_MOUSE_LL       = 14;
    23. /// <summary>
    24. /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard input events.
    25. /// </summary>
    26. private const int WH_KEYBOARD_LL    = 13;
    27.   在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:
    28. //install hook
    29. hMouseHook = SetWindowsHookEx(
    30. WH_MOUSE_LL, //原来是WH_MOUSE
    31. MouseHookProcedure,
    32. Marshal.GetHINSTANCE(
    33. Assembly.GetExecutingAssembly().GetModules()[0]),
    34. 0);
    35. //install hook
    36. hKeyboardHook = SetWindowsHookEx(
    37. WH_KEYBOARD_LL, //原来是WH_KEYBORAD
    38. KeyboardHookProcedure,
    39. Marshal.GetHINSTANCE(
    40. Assembly.GetExecutingAssembly().GetModules()[0]),
    41. 0);
    42.   这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:
    43.   下面是关于鼠标和键盘的两个Callback函数:
    44. private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
    45. {
    46. // if ok and someone listens to our events
    47. if ((nCode >= 0) && (OnMouseActivity != null))
    48. {
    49. //Marshall the data from callback.
    50. MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
    51. //detect button clicked
    52. MouseButtons button = MouseButtons.None;
    53. short mouseDelta = 0;
    54. switch (wParam)
    55. {
    56. case WM_LBUTTONDOWN:
    57. //case WM_LBUTTONUP:
    58. //case WM_LBUTTONDBLCLK:
    59. button = MouseButtons.Left;
    60. break;
    61. case WM_RBUTTONDOWN:
    62. //case WM_RBUTTONUP:
    63. //case WM_RBUTTONDBLCLK:
    64. button = MouseButtons.Right;
    65. break;
    66. case WM_MOUSEWHEEL:
    67. //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.
    68. //One wheel click is defined as WHEEL_DELTA, which is 120.
    69. //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
    70. mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
    71. //TODO: X BUTTONS (I havent them so was unable to test)
    72. //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,
    73. //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,
    74. //and the low-order word is reserved. This value can be one or more of the following values.
    75. //Otherwise, mouseData is not used.
    76. break;
    77. }
    78. //double clicks
    79. int clickCount = 0;
    80. if (button != MouseButtons.None)
    81. if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
    82. else clickCount = 1;
    83. //generate event
    84. MouseEventArgs e = new MouseEventArgs(
    85. button,
    86. clickCount,
    87. mouseHookStruct.pt.x,
    88. mouseHookStruct.pt.y,
    89. mouseDelta);
    90. //raise it
    91. OnMouseActivity(this, e);
    92. }
    93. //call next hook
    94. return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
    95. }
    96. private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
    97. {
    98. //indicates if any of underlaing events set e.Handled flag
    99. bool handled = false;
    100. //it was ok and someone listens to events
    101. if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
    102. {
    103. //read structure KeyboardHookStruct at lParam
    104. KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
    105. //raise KeyDown
    106. if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
    107. {
    108. Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
    109. KeyEventArgs e = new KeyEventArgs(keyData);
    110. KeyDown(this, e);
    111. handled = handled || e.Handled;
    112. }
    113. // raise KeyPress
    114. if (KeyPress != null && wParam == WM_KEYDOWN)
    115. {
    116. bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
    117. bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
    118. byte[] keyState = new byte[256];
    119. GetKeyboardState(keyState);
    120. byte[] inBuffer = new byte[2];
    121. if (ToAscii(MyKeyboardHookStruct.vkCode,
    122. MyKeyboardHookStruct.scanCode,
    123. keyState,
    124. inBuffer,
    125. MyKeyboardHookStruct.flags) == 1)
    126. {
    127. char key = (char)inBuffer[0];
    128. if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
    129. KeyPressEventArgs e = new KeyPressEventArgs(key);
    130. KeyPress(this, e);
    131. handled = handled || e.Handled;
    132. }
    133. }
    134. // raise KeyUp
    135. if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
    136. {
    137. Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
    138. KeyEventArgs e = new KeyEventArgs(keyData);
    139. KeyUp(this, e);
    140. handled = handled || e.Handled;
    141. }
    142. }
    143. //if event handled in application do not handoff to other listeners
    144. if (handled)
    145. return 1;
    146. else
    147. return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
    148. }

如何在C#中使用全局鼠标、键盘Hook的更多相关文章

  1. C#全局鼠标键盘Hook

    原文出自:http://www.cnblogs.com/iEgrhn/archive/2008/02/17/1071392.html using System; using System.Collec ...

  2. 如何在ArcMap中监听键盘鼠标事件(转)

    如何在ArcMap中监听键盘鼠标事件(转) Link: http://www.cnblogs.com/dyllove98/p/3155551.html 昨天有个朋友想要实现一个功能,就是在ArcMap ...

  3. 在C#中使用全局鼠标、键盘Hook

    今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全 ...

  4. 全局鼠标钩子:WH_MOUSE_LL, 在【 win 10 上网本】上因为太卡,运行中丢失全局鼠标钩子

    一台几年前买的上网本,让我安装了一个 win 10,然后用来测试程序的时候, 发现 使用 SetWindowsHookEx(WH_MOUSE_LL, mouseHook, GetModuleHandl ...

  5. 将CodedUI Test 放到控制台程序中,模拟鼠标键盘操作

    CodedUI Test是微软的自动化测试工具,在VS中非常好用.可以用来模拟鼠标点击,键盘输入.但执行的时候必须要用mstest调用,无法传入参数(当然可以写入config文件中,但每次修改十分麻烦 ...

  6. 如何在 pyqt 中实现全局事件总线

    前言 在 Qt 中可以使用信号和槽机制很方便地实现部件之间的通信,考虑下面这样的场景: 我想要点击任意一个专辑卡并通知主界面跳转到专辑界面,那么一种实现方式如上图所示:点击任意一个蓝色方框所示的专辑卡 ...

  7. 如何在ArcMap中监听键盘鼠标事件

    昨天有个朋友想要实现一个功能,就是在ArcMap中编辑数据的时候,能够通过快捷键自动设置预定义的属性,比如,选中若干要素,按A键,就自动填充属性,按B键,则又自动填充另外的属性字段. 单就这个功能而言 ...

  8. [No0000AC]全局鼠标键盘模拟器

    之前网上下载的一位前辈写的工具,名叫:Dragon键盘鼠标模拟器,网址http://www.esc0.com/. 本软件能够录制键盘鼠标操作,并能按要求回放,对于重复的键盘鼠标操作,可以代替人去做,操 ...

  9. 如何在Vue中建立全局引用或者全局命令

    1 一般在vue中,有很多vue组件,这些组件每个都是一个文件.都可能需要引用到相同模块(或者插件).我们不想每个文件都import 一次模块. 如果是基于vue.js编写的插件我们可以用 Vue.u ...

随机推荐

  1. Appium过程中用到的adb点滴知识库

    一.认识abd adb是什么? adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序,说白了就是d ...

  2. dzzoffice的树型结构用户管理设计

    在DzzOffice1.1的开发中,针对用户使用群体重新设计了,机构.部门.用户管理应用. 传统OA,企业相关程序,一般是设置机构-设置部门-设置职位-添加用户这样的步骤.每个步骤分为不同的管理界面. ...

  3. 一.JSP开发的工具下载与环境搭建

    JSP技术的强势: (1)一次编写,到处运行.在这一点上Java比PHP更出色,除了系统之外,代码不用做任何更改. (2)系统的多平台支持.基本上可以在所有平台上的任意环境中开发,在任意环境中进行系统 ...

  4. strcpy()的实现

    看到有一个博客讲的比平时理解的更深入,mark一下:strcpy函数的实现 这里只写平时理解的,三个要点: //strcpy自己实现 char *strcpy(char *dest, const ch ...

  5. 黑马程序员——经典C语言程序设计100例

    1.数字排列 2.奖金分配问题 3.已知条件求解整数 4.输入日期判断第几天 5.输入整数进行排序 6.用*号显示字母C的图案 7.显示特殊图案 8.打印九九口诀 9.输出国际象棋棋盘 10.打印楼梯 ...

  6. 转 毛笔字教程ps

    跟大家分享一下毛笔字怎么做出来的,主要通过字体和素材叠加,十分简单,喜欢的一起练习.做完记得交作业. 先看看最终效果: 在网上是不是经常看这些碉堡了的毛笔感觉是不是很羡慕啊,现在我就教大家怎么做出这样 ...

  7. ps闪闪发光的字 教程+自我练习

    本教程的文字效果非常经典.不仅是效果出色,创作思路及制作手法都堪称完美.作者并没有直接使用纹理素材,纹理部分都是用滤镜来完成.这需要很强的综合能力,非常值得学习和借鉴.最终效果 我的: 1.创建一个新 ...

  8. IOS 异步加载图片

    #import <Foundation/Foundation.h> #import "StringUtils.h" @interface ImageManager : ...

  9. javascript 作用域例子

    for(var i=0,l=url1.length;i<l;i++){ var url = url1[i]; setTimeout(function(){ window.open(url); } ...

  10. cocos2d-x使用python创建vs模板

    cocos2d-x 2.2推荐使用create_project.py创建工程,所有的平台都可以通过这个python文件创建工程.这个文件位置在源码cocos2d-x-2.2.2\tools\proje ...