c#调用钩子
1 概述
在c++中有钩子程序,但是在C#还没有对其进行封装,所以需要自己根据实际情况调用钩子。钩子在我的理解下是,通过初始化钩子与系统中消息映射建立某种关系,当点击鼠标或者键盘,就会通过钩子中的回调函数获取信息。
钩子分为全局钩子和私有钩子
2 编写流程
a 从c++中导入,需要自己添加导入函数。
代码为:
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern short GetKeyState(VirtualKeys nVirtKey);
b 定义委托和事件
为了方便在注册后,hook能获取消息,可以通过委托和事件。
//SetWindowsHookEx调用。
public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
//用于获取消息
private static HookProc MouseHookProcedure;
private static HookProc KeyboardHookProcedure;
事件 #region Events /// <summary>
/// 当用户移动鼠标,按下任意鼠标按钮或滚动的车轮
/// </summary>
public event MouseEventHandler OnMouseActivity;
/// <summary>
/// 发生时,用户按下一个键
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// 当用户按下并释放
/// </summary>
public event KeyPressEventHandler KeyPress;
/// <summary>
/// 当用户释放的关键
/// </summary>
public event KeyEventHandler KeyUp; #endregion
c 定义Hooktype
public enum HookType : int
{
WH_JOURNALRECORD = ,
WH_JOURNALPLAYBACK = ,
WH_KEYBOARD = ,//私有钩子定义
WH_GETMESSAGE = ,
WH_CALLWNDPROC = ,
WH_CBT = ,
WH_SYSMSGFILTER = ,
WH_MOUSE = ,
WH_HARDWARE = ,
WH_DEBUG = ,
WH_SHELL = ,
WH_FOREGROUNDIDLE = ,
WH_CALLWNDPROCRET = ,
WH_KEYBOARD_LL = ,//全局钩子定义
WH_MOUSE_LL =
}
d hook类的定义和实现
public HookApi(bool InstallMouseHook, bool InstallKeyboardHook)
{
Start(InstallMouseHook, InstallKeyboardHook);
} #region Hook Handling public void Start(bool InstallMouseHook, bool InstallKeyboardHook)
{
//定义鼠标钩子函数
if (hMouseHook == && InstallMouseHook)
{
//关联鼠标事件
MouseHookProcedure = new HookProc(MouseHookProc);
//IntPtr ha=Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
IntPtr ha = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
//注册为全局钩子,后面会讲解
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, ha, );
//hMouseHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure,IntPtr.Zero, 0); if (hMouseHook == )
{
int errorCode = Marshal.GetLastWin32Error();
Stop(true, false, false);
throw new Win32Exception(errorCode);
//throw new Exception(errorCode.ToString());
}
}
if (hKeyboardHook == && InstallKeyboardHook)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
//IntPtr ha = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
IntPtr ha = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, ha, );
//hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProcedure,IntPtr.Zero, 0);
if (hKeyboardHook == )
{
int errorCode = Marshal.GetLastWin32Error();
Stop(false, true, false);
throw new Win32Exception(errorCode);
//throw new Exception(errorCode.ToString());
}
}
} private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
{
if ((nCode >= ) && (OnMouseActivity != null))
{
MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct)); MouseButtons button = MouseButtons.None;
short mouseDelta = ;
switch (wParam)
{
case WM_LBUTTONDOWN:
//case WM_LBUTTONUP:
//case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;
case WM_RBUTTONDOWN:
//case WM_RBUTTONUP:
//case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
case WM_MOUSEWHEEL:
//如果消息是WM_MOUSEWHEEL,高阶字的mouseData成员车轮三角洲。
//点击一个车轮被定义为,这是120 WHEEL_DELTA
//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
mouseDelta = (short)((mouseHookStruct.mouseData >> ) & 0xffff);
//TODO: X BUTTONS (I havent them so was unable to test)
//如果消息是WM_XBUTTONUP WM_XBUTTONDOWN,WM_XBUTTONDBLCLK,WM_NCXBUTTONDOWN,WM_NCXBUTTONUP
//或WM_NCXBUTTONDBLCLK的,高阶字指定X键被按下或释放,
//低位字被保留。这个值可以是以下值中的一个或多个。
//否则,mouseData还没有使用。
break;
}
int clickCount = ;
if (button != MouseButtons.None)
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK)
clickCount = ;
else clickCount = ; MouseEventArgs e = new MouseEventArgs(button, clickCount, mouseHookStruct.pt.x, mouseHookStruct.pt.y, mouseDelta);
OnMouseActivity(this, e);
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
//键盘事件响应函数,在注册后,就可以在这函数添加响应
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
try
{
bool handled = false;
if ((nCode >= ) && (KeyDown != null || KeyUp != null || KeyPress != null))
{
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)
Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDown(this, e);
handled = handled || e.Handled;
}
if (KeyPress != null && wParam == WM_KEYDOWN)
{
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != ? true : false); byte[] keyState = new byte[];
GetKeyboardState(keyState);
byte[] inBuffer = new byte[];
if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == )
{
char key = (char)inBuffer[];
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key))
{
key = Char.ToUpper(key);
}
KeyPressEventArgs e = new KeyPressEventArgs(key);
KeyPress(this, e);
handled = handled || e.Handled;
}
}
if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUp(this, e);
handled = handled || e.Handled;
} }
if (handled)
return ;
else
return ;//CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
catch (Exception ex)
{
return -;
}
} public void Stop()
{
this.Stop(true, true, true);
}
//钩子卸载
public void Stop(bool UninstallMouseHook, bool UninstallKeyboardHook, bool ThrowExceptions)
{
if (hMouseHook != && UninstallMouseHook)
{
int retMouse = UnhookWindowsHookEx(hMouseHook);
hMouseHook = ;
if (retMouse == && ThrowExceptions)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode);
}
}
if (hKeyboardHook != && UninstallKeyboardHook)
{
int retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = ;
if (retKeyboard == && ThrowExceptions)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode);
}
}
}
e 钩子函数调用
HookApi hook ;
if (HcHook == null)
{
HcHook = new HookApi(false, true);
}
HcHook.KeyDown += new KeyEventHandler(HcHook_KeyDown);
HcHook.KeyUp += new KeyEventHandler(HcHook_KeyUp);
void HcHook_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
Cat.Log.FileLog.WriteMessage("CCVSifhtPanel中按下Ctrl");
FlagKeyborad = true;
} }
3 注意事项
下面备注一下在使用过程中一些类库说明及注意事项:
1、AppDomain.GetCurrentThreadId()在.net 2.0中过时了,VS2005和VS2008警告这个方法已经过时,建议使用System.Threading.Thread.CurrentThread.ManagedThreadId,但实际上这两个值是不一样的。AppDomain.GetCurrentThreadId()的实际上调用Win32 API,其返回的是该线程在Windows中的ThreadId,即同这个等价:
[DllImport("kernel32")]
public static extern int GetCurrentThreadId();
而System.Threading.Thread.CurrentThread.ManagedThreadId返回的是作为一个ManagedThread在.Net CLR中的ThreadId,所以这和Windows的ThreadId是完全不同的。
2、使用API函数SetWindowsHookEx()把一个应用程序定义的钩子子程安装到钩子链表中。SetWindowsHookEx函数总是在Hook链的开头安装Hook子程。当指定类型的Hook监视的事件发生时,系统就调用与这个Hook关联的Hook链的开头的Hook子程。每一个Hook链中的Hook子程都决定是否把这个事件传递到下一个Hook子程。Hook子程传递事件到下一个Hook子程需要调用CallNextHookEx函数.函数签名如下:
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
代码
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/ -->HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
// 或是一个由别的进程创建的线程的标识,
// lpfn必须指向DLL中的钩子子程。
// 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
// 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的
DLL。
// 如果dwThreadId 标识当前进程创建的一个线程,
// 而且子程代码位于当前进程,hMod必须为NULL。
// 可以很简单的设定其为本应用程序的实例句柄。
DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符。
// 如果为0,钩子子程与所有的线程关联,即为全局钩子。
);
函数成功则返回钩子子程的句柄,失败返回NULL。
以上所说的钩子子程与线程相关联是指在一钩子链表中发给该线程的消息同时发送给钩子子程,且被钩子子程先处理。
3、系统钩子和线程钩子:
SetWindowsHookEx()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子。
线程勾子用于监视指定线程的事件消息。线程勾子一般在当前线程或者当前线程派生的线程内。
系统勾子监视系统中的所有线程的事件消息。因为系统勾子会影响系统中所有的应用程序,所以勾子函数必须放在独立的动态链接库(DLL) 中。系统自动将包含”钩子回调函数”的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程。
几点说明:
(1)如果对于同一事件(如鼠标消息)既安装了线程勾子又安装了系统勾子,那么系统会自动先调用线程勾子,然后调用系统勾子。
(2)对同一事件消息可安装多个勾子处理过程,这些勾子处理过程形成了勾子链。当前勾子处理结束后应把勾子信息传递给下一个勾子函数。
(3)勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时卸载。
c#调用钩子的更多相关文章
- windows消息钩子注册底层机制浅析
标 题: [原创]消息钩子注册浅析 作 者: RootSuLe 时 间: 2011-06-18,23:10:34 链 接: http://bbs.pediy.com/showthread.php?t= ...
- php 添加钩子实例
<?php/*定义钩子函数*/function add($hook,$actionFunc){ global $emHooks; if(isset($emHooks[$hook])) ...
- WordPress 插件机制的简单用法和原理(Hook 钩子)
WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它. PS:本文只是简单的总结 ...
- C# Hook钩子实例代码之截取键盘输入,需要的朋友可以参考下
一.关于本文 以最通俗的语言说明钩子的使用方法,具体到钩子的详细介绍可以参照下面的网址: http://www.microsoft.com/china/community/program/origin ...
- C#钩子应用实例
C#钩子应用实例一.写在最前 本文的内容只想以最通俗的语言说明钩子的使用方法,具体到钩子的详细介绍可以参照下面的网址: http://www.microsoft.com/china/community ...
- HOOK钩子 - 钩子函数说明
翻译参考自MaybeHelios的blog: http://blog.csdn.net/maybehelios/ 通过SetWindowsHookEx方法安装钩子,该函数指定处理拦截消息的钩子函数(回 ...
- HOOK API (一)——HOOK基础+一个鼠标钩子实例
HOOK API (一)——HOOK基础+一个鼠标钩子实例 0x00 起因 最近在做毕业设计,有一个功能是需要实现对剪切板的监控和进程的防终止保护.原本想从内核层实现,但没有头绪.最后决定从调用层入手 ...
- 《windows核心编程系列》十八谈谈windows钩子
windows应用程序是基于消息驱动的.各种应用程序对各种消息作出响应从而实现各种功能. windows钩子是windows消息处理机制的一个监视点,通过安装钩子能够达到监视指定窗体某种类型的消息的功 ...
- VC6 鼠标钩子 最简单样例
Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的.而钩子是Windows系统中非常重要的系统接口,用它能够截获并处理送给其它应用程序的消息,来完毕普通应用程序 ...
随机推荐
- free() 是如何释放不同内存区块大小的指针?
最初是在知乎上看到这个问题的C++ delete[] 是如何知道数组大小的?,我也挺好奇,所以就作了一番工作. 申请内存时,指针所指向区块的大小这一信息,其实就记录在该指针的周围看下面这段代码: #i ...
- 在python 中有时候我们用数组
在python 中有时候我们用数组操作数据可以极大的提升数据的处理效率, 类似于R的向量化操作,是的数据的操作趋于简单化,在python 中是使用numpy模块可以进行数组和矢量计算. 下面来看下简单 ...
- Centos6.5安装
前奏:CentOS 6.5下载地址http://mirror.centos.org/centos/6.5/isos/x86_64/CentOS-6.5-x86_64-bin-DVD1to2.torre ...
- 关于python decode()和 encode()
1.先收集一下这几天看到的关于decode()解码和encode()编码的用法 bytes和str是字节包和字符串,python3中会区分bytes和str,不会混用这两个.字符串可以编码成字节包,而 ...
- Docker安装Gitlab
一.Ubuntu16.4上Docker安装Gitlab 1.安装docker 参见:https://docs.docker.com/engine/installation/linux/ubuntuli ...
- Python 手册——参数传递以及交互模式
我们先来看参数传递. 调用解释器时,脚本名和附加参数之传入一个名为sys.argv的字符串列表.没有脚本和参数时,它至少也有一个 元素:sys.argv[0]此时为空字符串.脚本名指定为‘ - ’(表 ...
- 练习2 E题 - 求奇数的乘积
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Description 给你n ...
- LightOj_1030 Discovering Gold
题目链接 题意: 在一个1 X N 的格子上, 每个格子都有一定的黄金, 你从第一个格子出发, 问到最后一个格子得到黄金的期望. 每次前进使用骰子投点来决定前进步数, 如果投出的点前进后会超过N, 那 ...
- [CF Round #294 div2] E. A and B and Lecture Rooms 【树上倍增】
题目链接:E. A and B and Lecture Rooms 题目大意 给定一颗节点数10^5的树,有10^5个询问,每次询问树上到xi, yi这两个点距离相等的点有多少个. 题目分析 若 x= ...
- 【转】python3 发邮件实例(包括:文本、html、图片、附件、SSL、群邮件)
特别留意群邮件方式,这是工作中用得多的. 附件,HTML,图片,都需要的. 文件形式的邮件 [python] view plain copy 1.#!/usr/bin/env python3 2.#c ...