今天,有个同事问我,怎样在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. 如何在C#中使用全局鼠标、键盘Hook

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

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

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

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

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

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

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

  6. Python——pyHook监听鼠标键盘事件

    pyHook包为Windows中的全局鼠标和键盘事件提供回调. 底层C库报告的信息包括事件的时间,事件发生的窗口名称,事件的值,任何键盘修饰符等. 而正常工作需要pythoncom等操作系统的API的 ...

  7. hook 鼠标键盘消息实例分析

    1.木马控制及通信方法包含:双管道,port重用.反弹技术.Hook技术,今天重点引用介绍一下hook的使用方法,hook信息后能够将结果发送到hacker邮箱等.实现攻击的目的. 转自:http:/ ...

  8. C#鼠标键盘钩子

    using System;using System.Collections.Generic; using System.Reflection; using System.Runtime.Interop ...

  9. 键盘Hook【Delphi版】

    原文:https://www.cnblogs.com/edisonfeng/archive/2012/05/18/2507858.html 一.钩子的基本概念 a) Hook作用:监视windows消 ...

随机推荐

  1. ajax连接池和XMLHttpRequest

    连接池 我们公司在路由和交换机web界面和后端交互全部采用的是自己封装的ajax组件完成的,组件有点老了,代码风格和其中的某些用法现在看起来都有点不习惯.今天把这个组件的核心部分的ajax连接池记录下 ...

  2. VM虚拟机快照还原效果实现方式

    ===================================================默认"快照删除"行为:============================ ...

  3. boost的link 和 runtime-link,搭配shared 和 static

    转自:http://blog.csdn.net/yasi_xi/article/details/8660549 link:生成动态链接库/静态链接库.生成动态链接库需使用shared方式,生成静态链接 ...

  4. DzzOffice结合office web Apps私有部署的实例

    很多朋友都想在自己使用的DzzOffice中,调用本地部署的office web Apps server. 下面我就直接从头到尾的将部署全部过程分享给大家. 准备条件:两台服务器,配置稍高点,以免卡顿 ...

  5. 二级指针的作用及用途 .xml

    pre{ line-height:1; color:#9f1d66; background-color:#e1e1e1; font-size:16px;}.sysFunc{color:#5d57ff; ...

  6. Tcl之group arguments

    1 doubel quotes This allows substitutions to occur within the quotations - or "interpolation&qu ...

  7. DOS 命令大全

    MS DOS 命令大全 一.基础命令 1 dir 无参数:查看当前所在目录的文件和文件夹. /s:查看当前目录已经其所有子目录的文件和文件夹. /a:查看包括隐含文件的所有文件. /ah:只显示出隐含 ...

  8. Yarn中的几种状态机

    1 概述 为了增大并发性,Yarn采用事件驱动的并发模型,将各种处理逻辑抽象成事件和调度器,将事件的处理过程用状态机表示.什么是状态机? 如果一个对象,其构成为若干个状态,以及触发这些状态发生相互转移 ...

  9. 第二百二十天 how can I 坚持

    今天如愿去了凤凰岭,比想象中的好多了.山好陡,都没有爬到山顶,下山时山都有点黑了,有点恐怖. 凤凰岭啊.有时间还得再去趟. 下周去八大处.坚持. 看什么时候能把北京这些山爬完,然后 三山五岳. 不爽. ...

  10. Spark RDD概念学习系列之RDD的转换(十)

    RDD的转换 Spark会根据用户提交的计算逻辑中的RDD的转换和动作来生成RDD之间的依赖关系,同时这个计算链也就生成了逻辑上的DAG.接下来以“Word Count”为例,详细描述这个DAG生成的 ...