今天,有个同事问我,怎样在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. Modularity模块化

    Modularity in this context refers to test scripts, whereas independence refers to test cases. Given ...

  2. XposedNoRebootModuleSample 不需要频繁重启调试的Xposed 模块源码例子

    XposedNoRebootModuleSample(不需要频繁重启调试的Xposed 模块源码例子) Xposed Module Sample No Need To Reboot When Debu ...

  3. 正则 提取html标签value

    using System.Text.RegularExpressions; //step2: extract expected info //<h1 class="h1user&quo ...

  4. erase() 返回的是删除此元素之后的下一个元素的迭代器 .xml

    pre{ line-height:1; color:#f0caa6; background-color:#2d161d; font-size:16px;}.sysFunc{color:#e54ae9; ...

  5. win7 共享的问题,"您可能没有权限使用网络资源"的解决办法

    重点来了,如果以上方法都不行的话,下面这个绝对有效,本人屡试不爽.1 打开受访者的guest权限2 开始--运行--gpedit.msc3 windows设置---安全设置--本地策略--用户权利指派 ...

  6. Floyd算法解决最短路径问题

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的中午,A和B在吃过中饭之后,来到了一个新的鬼屋!鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些 ...

  7. Wiki动画回顾系列序&&目录

    嘛,前前后后看了太多动画,我自己一直想做的事也是喜欢能做一款acg相关的应用,但一直没有好的点子,当然纠结到最后还是需要一个比较好的社区来让大家加入进来.一直有人让我给他们推番,而我也慢慢懂得“人心” ...

  8. 【转】requirejs简单入门

    博主今天正式工作啦,工作中用到了js模块化技术,这里转来一个入门教程,很易懂,转给同样刚入门的你们~~ 原地址:http://www.ruanyifeng.com/blog/2012/11/requi ...

  9. Juniti学习总结

    JUnit简介 JUnit是由 Erich Gamma和Kent Beck编写的一个回归测试框架(regression testing framework).JUnit测试是程序员测试,即所谓白盒测试 ...

  10. Linux_搜文件

    Linux 下搜文件, 通常先用 whereis 或 locate ,如果找不到,才以 find 搜寻!因为 whereis 与 locate 是利用数据库来搜寻数据,省时间! <<鸟哥的 ...