您的位置:首页 > 编程语言 > C#

深入分析C#键盘勾子(Hook)拦截器,屏蔽键盘活动的详解【方便自己学习查阅】

2015-10-09 16:58 453 查看


深入分析C#键盘勾子(Hook)拦截器,屏蔽键盘活动的详解

一些运行机制:

在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。

因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程 之间共享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些 变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。


系统钩子与线程钩子:

SetWindowsHookEx()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子。

线程勾子用于监视指定线程的事件消息。线程勾子一般在当前线程或者当前线程派生的线程内。

系统勾子监视系统中的所有线程的事件消息。因为系统勾子会影响系统中所有的应用程序,所以勾子函数必须放在独立的动态链接库(DLL) 中。系统自动将包含"钩子回调函数"的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程。

几点说明:

(1)如果对于同一事件(如鼠标消息)既安装了线程勾子又安装了系统勾子,那么系统会自动先调用线程勾子,然后调用系统勾子。

(2)对同一事件消息可安装多个勾子处理过程,这些勾子处理过程形成了勾子链。当前勾子处理结束后应把勾子信息传递给下一个勾子函数。

(3)勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时卸载

C#键盘勾子(Hook)拦截器,屏蔽键盘活动源代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using Microsoft.Win32;
namespace Vjsdn.Tech.KeyboardHook
{
public partial class frmKeyboardHook : Form
{
//勾子管理类
private KeyboardHookLib _keyboardHook = null;

public frmKeyboardHook()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//安装勾子
_keyboardHook = new KeyboardHookLib();
_keyboardHook.InstallHook(this.OnKeyPress);
}

private void button2_Click(object sender, EventArgs e)
{
//取消勾子
if (_keyboardHook != null) _keyboardHook.UninstallHook();
}

/// <summary>
/// 客户端键盘捕捉事件.
/// </summary>
/// <param name="hookStruct">由Hook程序发送的按键信息</param>
/// <param name="handle">是否拦截</param>
public void OnKeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle)
{
handle = false; //预设不拦截任何键

if (hookStruct.vkCode == 91) // 截获左win(开始菜单键)
{
handle = true;
}

if (hookStruct.vkCode == 92)// 截获右win
{
handle = true;
}

//截获Ctrl+Esc
if (hookStruct.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control)
{
handle = true;
}

//截获alt+f4
if (hookStruct.vkCode == (int)Keys.F4 && (int)Control.ModifierKeys == (int)Keys.Alt)
{
handle = true;
}

//截获alt+tab
if (hookStruct.vkCode == (int)Keys.Tab && (int)Control.ModifierKeys == (int)Keys.Alt)
{
handle = true;
}

//截获F1
if (hookStruct.vkCode == (int)Keys.F1)
{
handle = true;
}

//截获Ctrl+Alt+Delete
if ((int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt + (int)Keys.Delete)
{
handle = true;
}

//如果键A~Z
if (hookStruct.vkCode >= (int)Keys.A && hookStruct.vkCode <= (int)Keys.Z)
{
//挡掉B键
if (hookStruct.vkCode == (int)Keys.B)
hookStruct.vkCode = (int)Keys.None; //设键为0

handle = true;
}

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

}
}
}
KeyboardHookLib.cs

键盘管理类

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using Microsoft.Win32;
using System.Windows.Forms;
namespace Vjsdn.Tech.KeyboardHook
{
/// <summary>
/// 键盘Hook管理类, by www.vjsdn.com 易学原创
/// </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);
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: