让代码更简单

C#利用HOOK注册全局热键

重要:本文最后更新于2019-11-22 08:35:55,某些文章具有时效性,若有错误或已失效,请在下方留言或联系代码狗

C#利用HOOK注册全局热键的效果大家应该都见过,比如QQ的截图功能,即使QQ处于后台运行状态,仍然能获取键盘输入内容。要知道,C#程序在失去焦点的情况下KeyDown等键盘事件是得不到消息的,利用全局HOOK钩子技术就能在程序运行情况下,即使失去焦点,或者后台仍然能获取用户键盘输入内容。

C#利用HOOK注册全局热键

C#利用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,当然这里没使用注入功能,一般不会被杀的,最后警告大家不要做危害他人计算机的事哟~

感觉很棒!可以赞赏支持我哟~

3 打赏

评论 (1)

登录后评论
代码是好代码,就是搞得玄乎其技的。 笔锋好好改改,别自己抓着自己的头发飞到半空中了
QQ咨询 邮件咨询 狗哥推荐