MFC线程钩子和全局钩子[HOOK DLL]
第一部分:API函数简介
1. SetWindowsHookEx函数
函数原型
HHOOK SetWindowsHookEx(
int idHook, // hook type
HOOKPROC lpfn, // hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // thread identifier
);
函数功能:该函数将一个应用程序定义的挂钩处理过程安装到挂钩链中去,您可以通过安装挂钩处理过程来对系统的某些类型事件进行监控,这些事件与某个特定的线程或系统中的所有事件相关.具体参数详见MSDN;
举例:
线程钩子:
HHOOK g_hMouse;//全局变量,保存钩子的句柄
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
//……
}
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
2. CallNextHookEx函数
函数原型:
LRESULT CallNextHookEx(
HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);
函数功能:调用下一个钩子
3. UnhookWindowsHookEx
函数原型:
BOOL UnhookWindowsHookEx(
HHOOK hhk // handle to hook procedure
);
第二部分:HOOK与DLL
1.线程钩子的创建过程:
1. 声明一个全局的HHOOK类型的变量,用于保存创建钩子的句柄,如:
HHOOK g_hMouse;//全局变量,保存钩子的句柄
2. 在应用程序的初始化函数中,安装钩子;注意SetWindowsHookEx的参数!
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
3. 编写处理钩子消息的回调函数:
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
//编写需要处理的部分
return 1;
//不需要处理的部分,调用
return CallNextHookEx(g_hMouse, nCode, wParam, lParam);
}
4. 卸载钩子函数
UnhookWindowsHookEx(g_hMouse);
2.系统钩子的创建过程:
运行机制:DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。#pragma data_seg预处理指令用于设置共享数据段。例如:
#pragma data_seg("SharedDataName")
HHOOK hHook=NULL;
#pragma data_seg()
在#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。再加上一条指令
#pragma comment(linker,"/section:.SharedDataName,rws")
那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。
系统钩子的创建需要将钩子的放在DLL中,因此其重建构成需要两部分:1.编写程序,生成Dll;2.编写应用程序调用Dll中的函数
2.1 DLL中的代码的编写
方案 1:源代码:http://download.csdn.net/detail/nuptboyzhb/4202102
1. 新建一个扩展MFC类型DLL工程;
2. 将DLL的句柄参数和要安装钩子的句柄声明为共享数据:
#pragma data_seg("Titlename") //名称任意起
HHOOK glhHook=NULL; //安装的鼠标钩子句柄
HINSTANCE glhInstance=NULL;//DLL实例句柄
#pragma data_seg()
注意:共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。
3. 新建一个CMouseHook的导出类,用于实现钩子的安装和卸载
class AFX_EXT_CLASS CMouseHook:public CObject //AFX_EXT_CLASS宏声明类为导出类
{
public:
CMouseHook();//钩子类的构造函数
~CMouseHook();//钩子类的析构函数
BOOL StartHook(HWND hWnd);//安装钩子函数
BOOL StopHook();//卸载钩子函数
};
注意:AFX_EXT_CLASS用于声明该类为导出类;
4. 编写安装钩子,卸载钩子,钩子过程的函数
安装钩子:glhHook=SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0);
卸载钩子:UnhookWindowsHookEx(glhHook);
钩子过程:
//鼠标钩子函数的实现
LRESULT CALLBACK MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
{
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lparam;
if (nCode>=0)
{
//处理过程的代码…..
}
return CallNextHookEx(glhHook,nCode,wparam,lparam); //继续传递消息
}
2.2 主程序的调用
新建一个应用程序,将上述生成的.dll文件和.lib文件及类声明的文件.h拷贝到当前目录中,并在头文件中包含生成的类声明.h文件;静态方式加载动态链接库
#pragma comment(lib,"MousehookDll.lib") //隐式链接DLL
然后就可以声明一个由DLL文件导出的类CMouseHook的一个变量;然后在应用程序的初始化函数中调用该变量的StartHook函数安装钩子;在需要取消钩子的地方,调用StopHook()函数;
附录:钩子过程函数参数详解
从上面的步骤中可以看到,钩子的安装和卸载是一个较为固定格式和步骤;真正关键的是:不同的钩子类型,回调函数的参数意义不同,那我们就一一介绍各个参数的意义吧!
a. MouseProc(int nCode,WPARAM wparam,LPARAM lparam)WH_MOUSE
1.nCode 跟所有其他钩子处理函数一样,只要记得当 nCode小于0时:调用CallNextHookEx()就可以了。
HC_ACTION 当nCode等于HC_ACTION时,wParam和lParam 包含鼠标信息 HC_NOREMOVE 当nCode等于HC_NOREMOVE时,wParam和lParam 包含鼠标信息,并且鼠标消息没有从消息队列里移除
2. wParam 指定鼠标消息ID
3. lParam 一个MOUSEHOOKSTRUCT 结构的指针
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; //保存鼠标在屏幕上的x,y坐标
HWND hwnd; //接收到鼠标消息的窗口的句柄
UINT wHitTestCode; //详细描述参见WM_NCHITTEST消息
ULONG_PTR dwExtraInfo; //指定与本消息联系的额外消息
} MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
b. KeyboardProc(int nCode,WPARAM wparam,LPARAM lparam) WH_KEYBOARD
2.wParam:按键的虚拟键值消息,例如:VK_F1 VK_F2 等;
3. lParam:32位内存,内容描述包括:指定扩展键值,扫描码,上下文,重复次数。
0-15位:描述:按下键盘次数。
16-23位:指定扫描码. 依赖于OEM
24位:当24位为1时候:表示按键是扩展键;当24位为0时候:表示按键是数字键盘按键
25-28位:保留位
29位:上下文键:为1时: ALT按下,其他情况为0
30位:如果是按键按下后发送的消息,30位为0,如果是按键抬起后30位为1;
31位:指定转变状态;31位为0时候,按键正在被按下,为1时候,按键正在被释放
c. GetMsgProc(int nCode,WPARAM wparam,LPARAM lparam) WH_GETMESSAGE
2.wParam:标明消息是否从消息对列中取出,它有如下两个值:
PM_NOREMOVE:未从消息队列中取出
PM_REMOVE:已经从消息队列中取出
3. lParam: 它是指向MSG结构体的一个指针
typedef struct tagMSG {
HWND hwnd; //接收消息的窗口句柄
UINT message; //消息的标识,如WM_CLOSE等
WPARAM wParam;// 指定消息的附加信息
LPARAM lParam; // 不同的消息不一样;
DWORD time; //消息投递到消息队列中的时间
POINT pt; //消息投递到消息队列中时的鼠标位置(屏幕坐标)
} MSG, *PMSG;
d. 未完待续…
MFC线程钩子和全局钩子[HOOK DLL]的更多相关文章
- git自定义项目钩子和全局钩子
钩子介绍 自定义钩子分为:项目钩子和全局钩子 自定义全局钩子: 全局钩子目录结构: (注意:excludes目录结构是我们自定义的目录,规则逻辑在update.d/update.py脚本里实现的,非g ...
- Django12-ModelForm中创建局部钩子和全局钩子
一.局部钩子 命名规则为clean_对象名称,例如上面定义了username.pwd对象,那么可以定义clean_username.clean_pwd的局部钩子进行规则校验 1.例子:定义一个手机号校 ...
- form表单钩子,局部钩子和全局钩子
form表单源码解析: 局部钩子: 全局钩子:
- Django学习笔记(14)——AJAX与Form组件知识补充(局部钩子和全局钩子详解)
我在之前做了一个关于AJAX和form组件的笔记,可以参考:Django学习笔记(8)——前后台数据交互实战(AJAX):Django学习笔记(6)——Form表单 我觉得自己在写Django笔记(8 ...
- Django框架(十四)-- forms组件、局部钩子、全局钩子
一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语 ...
- Django框架(十五)—— forms组件、局部钩子、全局钩子
目录 forms组件.局部钩子.全局钩子 一.什么是forms组件 二.forms组件的使用 1.使用语法 2.组件的参数 3.注意点 三.渲染模板 四.渲染错误信息 五.局部钩子 1.什么是局部钩子 ...
- django----利用Form 实现两次密码输入是否一样 ( 局部钩子和全局钩子 )
from django import forms # 导入表单模块 from django.core.exceptions import ValidationError class RegisterF ...
- ModelForm错误验证自定义钩子和全局钩子
当需要对model_class中字段作进一步验证,作进一步的约束时,需要使用到钩子,即claan_xxx和clean方法.其返回的errors有点不是那么好处理.看示例. 1.Model_clas ...
- Django学习笔记之form组件的局部钩子和全局钩子
本文通过注册页面的form组件,查看其中使用的全局钩子和局部钩子. # Create your views here. class RegForm(forms.Form): username = fo ...
随机推荐
- MSSQL Server 导入/导出到远程服务器
1.打开本地企业管理器,先创建一个SQL Server注册来远程连接服务器端口SQL Server. 步骤如下图: 图1: 2.弹出窗口后输入内容."总是提示输入登陆名和密码"可选 ...
- Linux 最常用命令小结
1. 文件共享 1).将windows 系统下的文件夹共享到linux的方法: 安装filezilla,设置连接linux 服务器.将文件上传. 2).mRemote 机器连接管理 2. 文件管理命令 ...
- 第六十五篇、OC_iOS7 自定义转场动画push pop
自定义转场动画,在iOS7及以上的版本才开始出现的,在一些应用中,我们常常需要定制自定义的的跳转动画 1.遵守协议:<UIViewControllerAnimatedTransitioning& ...
- 第三十六篇、webService
在很多的情况下,我们会常常遇到webservive写的接口,往往这种情况下,我们就需要拼接一段报文去与服务器对接 首先要明白webService的工作原理,,,(http://www.cnblogs. ...
- out ref区别
1.使用ref型参数时,传入的参数必须先被初始化.对out而言,必须在方法中对其完成初始化. 2.out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候. ...
- POJ 2528 Mayor’s posters
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37982 Accepted: 11030 ...
- KMeans聚类算法Hadoop实现
Assistance.java 辅助类,功能详见注释 package KMeans; import org.apache.hadoop.conf.Configuration; import org. ...
- mysql 触发器,insert,auto字段竟然一样....
a 表的字段有id,uid,name,其中id是自增值, CREATE TRIGGER trigger_insert_productAFTER INSERT ON aFOR EACH ROWBEGIN ...
- 利用Linux下的pthread_mutex_t类型来实现哲学家进餐问题
首先说一下什么是哲学家进餐问题,这是操作系统课程中一个经典的同步问题, 问题如下:如上图,有6个哲学家和6根筷子(那个蓝色部分表示哲学家,那个紫色长条部分表示筷子),他们分别被编了0~5的号!如果某个 ...
- 开发问题记录——ArcEngine问题记录
ArcEngine 使用Winform进行坐标投影变换,用到AE空间,出现如下错误: “ESRI.ArcGIS.esriSystem.IXMLSerialize”在未被引用的程序集中定义.必须添加 ...