winform C#键盘钩子(Hook)拦截器,屏蔽键盘深入解析

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

运行机制
1、钩子链表和钩子子程:

每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程 序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。 一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始, 而最早安装的钩子放在最后,也就是后加入的先获得控制权。

Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。

钩子子程是一个应用程序定义的回调函数(CALLBACK Function),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。

KeyboardHook.cs 类

public class KeyboardHook

{

private const int WH_KEYBOARD_LL = 13; //键盘

//键盘处理事件委托 ,当捕获键盘输入时调用定义该委托的方法.

private delegate int HookHandle(int nCode, int wParam, IntPtr lParam);

//客户端键盘处理事件

public delegate void ProcessKeyHandle(HookStruct param, out bool handle);

//接收SetWindowsHookEx返回值

private static int _hHookValue = 0;

//勾子程序处理事件

private HookHandle _KeyBoardHookProcedure;

//Hook结构

StructLayout(LayoutKind.Sequential)

public class HookStruct

{

public int vkCode;

public int scanCode;

public int flags;

public int time;

public int dwExtraInfo;

}

//设置钩子

DllImport("user32.dll")

private static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hInstance, int threadId);

//取消钩子

DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)

private static extern bool UnhookWindowsHookEx(int idHook);

//调用下一个钩子

DllImport("user32.dll")

private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);

//获取当前线程ID

DllImport("kernel32.dll")

private static extern int GetCurrentThreadId();

//Gets the main module for the associated process.

DllImport("kernel32.dll")

private static extern IntPtr GetModuleHandle(string name);

private IntPtr _hookWindowPtr = IntPtr.Zero;

//构造器

public KeyboardHook() { }

//外部调用的键盘处理事件

private static ProcessKeyHandle _clientMethod = null;

/// <summary>

/// 安装勾子

/// </summary>

/// <param name="hookProcess">外部调用的键盘处理事件</param>

public void InstallHook(ProcessKeyHandle clientMethod)

{

_clientMethod = clientMethod;

// 安装键盘钩子

if (_hHookValue == 0)

{

_KeyBoardHookProcedure = new HookHandle(OnHookProc);

_hookWindowPtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

_hHookValue = SetWindowsHookEx(

WH_KEYBOARD_LL,

_KeyBoardHookProcedure,

_hookWindowPtr,

0);

//如果设置钩子失败.

if (_hHookValue == 0) UninstallHook();

}

}

//取消钩子事件

public void UninstallHook()

{

if (_hHookValue != 0)

{

bool ret = UnhookWindowsHookEx(_hHookValue);

if (ret) _hHookValue = 0;

}

}

//钩子事件内部调用,调用_clientMethod方法转发到客户端应用。

private static int OnHookProc(int nCode, int wParam, IntPtr lParam)

{

if (nCode >= 0)

{

//转换结构

HookStruct hookStruct = (HookStruct)Marshal.PtrToStructure(lParam, typeof(HookStruct));

if (_clientMethod != null)

{

bool handle = false;

//调用客户提供的事件处理程序。

_clientMethod(hookStruct, out handle);

if (handle) return 1; //1:表示拦截键盘,return 退出

}

}

return CallNextHookEx(_hHookValue, nCode, wParam, lParam);

}

}

Form窗体

  1. public partial class Form1 : Form

  2. {

  3. //勾子管理类

  4. private KeyboardHookLib _keyboardHook = null;

  5. public frmKeyboardHook()

  6. {

  7. InitializeComponent();

  8. }

  9. private void button1_Click(object sender, EventArgs e)

  10. {

  11. //安装勾子

  12. _keyboardHook = new KeyboardHookLib();

  13. _keyboardHook.InstallHook(this.OnKeyPress);

  14. }

  15. private void button2_Click(object sender, EventArgs e)

  16. {

  17. //取消勾子

  18. if (_keyboardHook != null) _keyboardHook.UninstallHook();

  19. }

  20. /// <summary>

  21. /// 客户端键盘捕捉事件.

  22. /// </summary>

  23. /// <param name="hookStruct">由Hook程序发送的按键信息</param>

  24. /// <param name="handle">是否拦截</param>

  25. public void OnKeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle)

  26. {

  27. handle = false; //预设不拦截任何键

  28. if (hookStruct.vkCode == 91) // 截获左win(开始菜单键)

  29. {

  30. handle = true;

  31. }

  32. if (hookStruct.vkCode == 92)// 截获右win

  33. {

  34. handle = true;

  35. }

  36. //截获Ctrl+Esc

  37. if (hookStruct.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control)

  38. {

  39. handle = true;

  40. }

  41. //截获alt+f4

  42. if (hookStruct.vkCode == (int)Keys.F4 && (int)Control.ModifierKeys == (int)Keys.Alt)

  43. {

  44. handle = true;

  45. }

  46. //截获alt+tab

  47. if (hookStruct.vkCode == (int)Keys.Tab && (int)Control.ModifierKeys == (int)Keys.Alt)

  48. {

  49. handle = true;

  50. }

  51. //截获F1

  52. if (hookStruct.vkCode == (int)Keys.F1)

  53. {

  54. handle = true;

  55. }

  56. //截获Ctrl+Alt+Delete

  57. if ((int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt + (int)Keys.Delete)

  58. {

  59. handle = true;

  60. }

  61. //如果键A~Z

  62. if (hookStruct.vkCode >= (int)Keys.A && hookStruct.vkCode <= (int)Keys.Z)

  63. {

  64. //挡掉B键

  65. if (hookStruct.vkCode == (int)Keys.B)

  66. hookStruct.vkCode = (int)Keys.None; //设键为0

  67. handle = true;

  68. }

  69. Keys key = (Keys)hookStruct.vkCode;

  70. label1.Text = "你按下:" + (key == Keys.None ? "" : key.ToString());

  71. }

  72. }

相关推荐
“抚琴”的人16 小时前
【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】
c#·工业相机·visionpro·机械视觉
FAREWELL0007518 小时前
C#核心学习(七)面向对象--封装(6)C#中的拓展方法与运算符重载: 让代码更“聪明”的魔法
学习·c#·面向对象·运算符重载·oop·拓展方法
CodeCraft Studio18 小时前
Excel处理控件Spire.XLS系列教程:C# 合并、或取消合并 Excel 单元格
前端·c#·excel
勘察加熊人20 小时前
forms实现连连看
c#
hvinsion20 小时前
PPT助手:一款集计时、远程控制与多屏切换于一身的PPT辅助工具
c#·powerpoint·ppt·ppt助手·ppt翻页
weixin_3077791321 小时前
使用C#实现从Hive的CREATE TABLE语句中提取分区字段名和数据类型
开发语言·数据仓库·hive·c#
时光追逐者1 天前
在 Blazor 中使用 Chart.js 快速创建数据可视化图表
开发语言·javascript·信息可视化·c#·.net·blazor
与火星的孩子对话1 天前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
response_L1 天前
国产系统统信uos和麒麟v10在线打开word给表格赋值
java·c#·word·信创·在线编辑
MasterNeverDown1 天前
Swagger2Md:让WebAPI文档生成变得轻松高效
c#