C#利用HOOK注册全局热键的效果大家应该都见过,比如QQ的截图功能,即使QQ处于后台运行状态,仍然能获取键盘输入内容。要知道,C#程序在失去焦点的情况下KeyDown等键盘事件是得不到消息的,利用全局HOOK钩子技术就能在程序运行情况下,即使失去焦点,或者后台仍然能获取用户键盘输入内容。
为了方便,清晰的看到HOOK的获取消息、拦截消息的能力,我这里分别使用两个标签lable
来显示来自HOOK的消息与来自按钮button3
的键盘消息。当按下HOOK不拦截消息时,标签1与标签2的内容是一样的,当按下HOOK拦截的消息时,按钮的KeyDown
事件将接收不到来自用户的按键信息。
C#代码
KeyboardHookLib.cs键盘HOOK管理类:
复制
/// <summary> /// 键盘Hook管理类 /// </summary> public class KeyboardHookLib { 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 KeyboardHookLib() { } //外部调用的键盘处理事件 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); } }
在Form1_Load事件中注册安装HOOK或者在按钮点击事件中注册安装HOOK。
复制
_keyboardHook = new KeyboardHookLib(); _keyboardHook.InstallHook(this.OnKeyPress);
注意声明全局变量
复制
KeyboardHookLib _keyboardHook;
HOOK处理方法
复制
/// <summary> /// 客户端键盘捕捉事件. /// </summary> /// <param name="hookStruct">由Hook程序发送的按键信息</param> /// <param name="handle">是否拦截</param> public void OnKeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle) { //是否拦截这个键 handle = false; Keys key = (Keys)hookStruct.vkCode; if (key.ToString() == "F8") { //拦截F8 handle = true; } else if (key.ToString() == "F12") { //拦截F12 handle = true; } label1.Text = "HOOK按下了:" + key; }
在按钮3的KeyDown事件中写下获取按键代码:
复制
label2.Text = "按下了:" + e.KeyCode;
在关闭窗口事件Form1_FormClosed或者按钮点击事件中卸载HOOK
复制
if (_keyboardHook != null) _keyboardHook.UninstallHook();
到此整个HOOK全局热键与KeyDown的效果程序完成,至于HOOK全局热键能干嘛,就要看大家怎么用了,心理阴暗的人就把它当做键盘记录器使用,偷偷记录别人的输入内容,截获各种密码隐私等。哈哈哈,别试了,杀软第一个杀的就是HOOK,当然这里没使用注入功能,一般不会被杀的,最后警告大家不要做危害他人计算机的事哟~
评论 (1)