什么是勾子  

 在Windows系统中,勾子(hook)是一种特殊的消息处理机制。勾子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。这样,我们就可以在系统中安装自定义的勾子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。可见,利用勾子可以实现许多特殊而有用的功能。因此,对于高级编程人员来说,掌握勾子的编程方法是很有必要的。

勾子的类型

 1. 按事件分类,有如下的几种常用类型

  (1) 键盘勾子和低级键盘勾子可以监视各种键盘消息。

  (2) 鼠标勾子和低级鼠标勾子可以监视各种鼠标消息。

  (3) 外壳勾子可以监视各种Shell事件消息。比如启动和关闭应用程序。

  (4) 日志勾子可以记录从系统消息队列中取出的各种事件消息。

  (5) 窗口过程勾子监视所有从系统消息队列发往目标窗口的消息。

  此外,还有一些特定事件的勾子提供给我们使用,不一一列举。

 2. 按使用范围分类,主要有线程勾子和系统勾子

  (1) 线程勾子监视指定线程的事件消息。

  (2) 系统勾子监视系统中的所有线程的事件消息。因为系统勾子会影响系统中所有的应用程序,所以勾子函数必须放在独立的动态链接库(DLL) 中。这是系统勾子和线程勾子很大的不同之处。

   几点需要说明的地方:  

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

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

  (3) 勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时卸载。 编写勾子程序    编写勾子程序的步骤分为三步:定义勾子函数、安装勾子和卸载勾子。   1.定义勾子函数   勾子函数是一种特殊的回调函数。勾子监视的特定事件发生后,系统会调用勾子函数进行处理。不同事件的勾子函数的形式是各不相同的。

下面以鼠标勾子函数举例说明勾子函数的原型:

LRESULT CALLBACK MouseProc ( int nCode, WPARAM wParam, LPARAM lParam)  

 参数wParam和 lParam包含鼠标消息的信息,比如鼠标位置、状态等。

nCode包含有关消息本身的信息,比如是否从消息队列中移出。

我们先在勾子函数中实现自定义的功能,然后调用函数 CallNextHookEx.把勾子信息传递给勾子链的下一个勾子函数。

CallNextHookEx.的原型如下: LRESULT CallNextHookEx ( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam )

 参数 hhk是勾子句柄。nCode、wParam和lParam 是勾子函数。

下面的例子是一个简单的监视鼠标消息的勾子函数: LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam) { //跟踪鼠标移动时的位置变化信息 if(wParam==WM_MOUSEMOVE || wParam== WM_NCMOUSEMOVE) { //是鼠标移动消息 point=((MOUSEHOOKSTRUCT *) lParam)->pt;//取鼠标信息 TRACE2(“Position is :%d,Y:%d/n",point.x,point.y); } //传递勾子信息 return CallNextHookEx(hHook,nCode,wParam,lParam); }   

2.安装勾子   在程序初始化的时候,调用函数SetWindowsHookEx安装勾子。

其函数原型为:

HHOOK SetWindowsHookEx ( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )  

 参数

idHook表示勾子类型,它是和勾子函数类型一一对应的。比如,WH_KEYBOARD表示安装的是键盘勾子,WH_MOUSE表示是鼠标勾子等等。   

Lpfn是勾子函数的地址。

HMod是勾子函数所在的实例的句柄。对于线程勾子,该参数为NULL;对于系统勾子,该参数为勾子函数所在的DLL句柄。  

dwThreadId 指定勾子所监视的线程的线程号。对于全局勾子,该参数为NULL。   SetWindowsHookEx返回所安装的勾子句柄。

3.卸载勾子    当不再使用勾子时,必须及时卸载。

简单地调用函数 BOOL UnhookWindowsHookEx( HHOOK hhk)即可。

  值得注意的是线程勾子和系统勾子的勾子函数的位置有很大的差别。线程勾子一般在当前线程或者当前线程派生的线程内,而系统勾子必须放在独立的动态链接库中,实现起来要麻烦一些。 线程勾子的编程实例   按照上面介绍的方法实现一个线程级的鼠标勾子。勾子跟踪当前窗口鼠标移动的位置变化信息。并输出到窗口。  

  (1)在VC++6.0中利用MFC APPWizard(EXE)生成一个不使用文档/视结构的单文档应用mousehook。打开childview.cpp文件,加入全局变量: HHOOK hHook;//鼠标勾子句柄 CPoint point;//鼠标位置信息 CChildView *pView; // 鼠标勾子函数用到的输出窗口指针   在CChildView::OnPaint()添加如下代码: CPaintDC dc(this); char str[256]; sprintf(str,“x=%d,y=%d",point.x,point.y); //构造字符串 dc.TextOut(0,0,str); //显示字符串

 (2)childview.cpp文件中定义全局的鼠标勾子函数。

LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam)

{//是鼠标移动消息

if(wParam==WM_MOUSEMOVE||wParam ==WM_NCMOUSEMOVE)

{

point=((MOUSEHOOKSTRUCT *)lParam)->pt; //取鼠标信息

pView->Invalidate(); //窗口重画

}

return CallNextHookEx(hHook,nCode,wParam,lParam); //传递勾子信息

}

(3)CChildView类的构造函数中安装勾子。

CChildView::CChildView()

{

pView=this;//获得输出窗口指针

hHook=SetWindowsHookEx (WH_MOUSE,MouseProc,0,GetCurrentThreadId());

}

(4)CChildView类的析构函数中卸载勾子。

CChildView::~CChildView()

{

if(hHook) UnhookWindowsHookEx(hHook);

}

系统勾子的编程实例   

编写系统勾子与编写线程勾子的步骤相似,不过必须把勾子函数放在DLL中。因此,读者需要了解编写动态链接库的基础知识。这里的例子实现一个系统级的键盘勾子,监视系统中所有应用的键盘输入消息并记录在文件中。这样需要两个工程,一个是主程序,一个是动态链接库。  

 (1)在DLL中定义键盘勾子函数。   在VC++6.0中利用MFC APPWizard(DLL)生动态链接库工程keyhook。然后选择DLL 的类型为使用共享MFC DLL的常规DLL。

打开 keyhook.cpp文件,加入全局说明:

#pragma data_seg(“SharedVar") //DLL输出的全局变量

extern “C" __declspec(dllexport) HHOOK hHook=NULL;

#pragma data_seg() // DLL 自用的全局变量

char buffer=0;

FILE *fl; 定义全局的键盘勾子函数: //DLL输出的勾子函数

extern “C" __declspec(dllexport) LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, //虚键代码 LPARAM lParam // 击键消息的信息 )

{

if(lParam&0x80000000)

{//如果某键按下

buffer=MapVirtualKey(wParam,2); // 把虚键代码变为字符 //输出到文件

fl=fopen( “keyfile.txt", “a+" );

fwrite(&buffer, sizeof(char), 1, fl); fclose(fl);

}

return CallNextHookEx(hHook,nCode,wParam,lParam);

}

  编译得到keyhook.dll和库文件keyhook.lib 。使用 keyhook.lib是为了让主程序可以方便地隐式调用DLL中的输出函数。   

(2)在VC++6.0中利用MFC APPWizard(EXE)生成一个不使用文档/视结构单文档应用getkey。

打开MainFrm.cpp文件。加入全局的输入变量和函数的说明: //要从DLL中输入的变量和函数

extern “C" __declspec(dllimport) HHOOK hHook;// extern “C" __declspec(dllimport) LRESULT CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam);   

(3)在CMainFrame类的构造函数中安装勾子。

CMainFrame::CMainFrame() { hHook=SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle(“keyhook.dll"), 0); }   

(4)在CMainFrame类的析构函数中卸载勾子。
CMainFrame::~CMainFrame()
{
    if(hHook)
      UnhookWindowsHookEx(hHook);
}   

编译这个工程的时候,注意包含第一步得到的库文件 keyhook.lib。keyhook.dll和getkey.exe应放在同一目录下运行。

用VC++编写勾子程序相关推荐

  1. 用VC++编写勾子程序(转)

    在Windows系统中,勾子(hook)是一种特殊的消息处理机制.勾子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理.这样,我们就可以在系统中安装自定义的勾子,监视系统中特定事件 ...

  2. VC编写的程序不能在其他机器上运行的解决方案(续)

    我在前面的文章里面提到由于side-by-side问题导致的VC编写的程序不能正常启动的问题的解决方案,这种方法是针对于单个可执行文件的解决方案,但是有的时候你可能会碰到另外一种情况-也是由于side ...

  3. VC++编写电子邮件程序 第二篇 也是用simple mapi

    VC++编写电子邮件程序 一.概述 ---- 本文主要讲述如何使用Visual C++用MAPI编写E-mail程序.MAPI是包含在Windows之中的, 因此不需要安装其他额外的部件.MAPI有以 ...

  4. VC编写的程序不能在其他机器上运行的解决方案

    有的时候,你在Visual C++上面经过好几个月的辛勤努力,终于将程序编写完成并且测试完毕,然而当你试图在客户的发布机上运行刚写好的程序时,有可能会碰到类似下面的错误,操作系统告诉你"由于 ...

  5. VC++ 隐藏控制台程序窗口

    转自:http://hi.baidu.com/sicceer/blog/item/d9c35a810d15c4c8bc3e1ec8.html 设置 #pragma comment( linker, & ...

  6. vc下c语言网络编程,用VC编写C/S消息传送程序

    下载本文示例代码 网络编程已经成为一种时髦,以TCP/IP协议的网络更为流行.自己编一个服务器与客户机互相传送消息的程序,以便增加自己网络编程的经验.下面我就介绍一下我编的程序. 首先介绍服务器程序: ...

  7. VC编写程序在debug下正常,在release下错误

    Debug 和 Release 编译方式的区别 Debug 和 Release 的真正秘密,在于一组编译选项.下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要, ...

  8. VC++编写USB接口通讯程序

    用VC++编写USB接口通讯程序 摘要:详细介绍Visual C++ 6.0环境下利用Windows API(Application Program Interface)函数来实现与符合HID设备类的 ...

  9. 【181221】VC 编写的网址收藏夹程序(Access)源代码

    源码下载简介 VC 编写的网址收藏夹程序(Access),网络小工具,碰到一些好的网址可以方便记录下来,程序极其简单,高手可不看,刚学习VC的朋友用来学习数据库的简单操作还可以,它可以练习数据库记录的 ...

最新文章

  1. Interpreter - 解释器模式
  2. python学生管理系统-Python 学生信息管理系统 2.0
  3. mysql dml 日志_Oracle DML错误日志笔记
  4. [云炬创业基础笔记]第七张创业团队测试8
  5. 运筹学广泛的使用计算机,运筹学笔记
  6. 2017.1.20活动
  7. C++程序设计方法3:移动构造函数
  8. CSS快速学习9:浏览器兼容
  9. 一图读懂|H3C SecPath ACG1050-X1应用控制网关
  10. oracle共享内存不足,Oracle数据库共享内存分配不足怎么办
  11. 使用CoreTelephony获得SIM卡网络运营商名称
  12. 基于深度学习的AI疲劳检测系统
  13. 中国微电网市场趋势报告、技术动态创新及市场预测
  14. 系统管理员设置了系统策略禁止进行此安装怎么解决
  15. 移动端安卓和苹果手机背景图片显示不全的问题
  16. 精密测量和超精密测量
  17. 一种更简单的求最小平方均值函数(MSE)的方法 -- 梯度下降法。
  18. 利用机器学习分析脑电数据(原理分析+示例代码+快速上手)
  19. excel网页服务器端,Excel服务VI――用Excel Web Services创建应用程
  20. 5G工业级路由器的常见接口功能解析

热门文章

  1. 《Decoders Matter for Semantic Segmentation》论文笔记
  2. 控制继电器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  3. kingroot pc版 v3.2.0.1129官方电脑版
  4. 使用Pythontutor学习Python
  5. C++11新特性:using和namespace的特殊用处
  6. Python爬虫笔记(1)--对新笔趣阁进行爬取
  7. 【vue】处理数组,无关联父id的情况下,根据特定条件区分父子项,单独给子项加事件
  8. 在ASP 调用 VB.net 编写的dll 出错 提示:Microsoft VBScript 运行时错误 错误 '800a01ad' ActiveX 部件不能创建对象
  9. jsp旅行社签证业务系统_基于jsp的旅行社管理-JavaEE实现旅行社管理 - java项目源码...
  10. 脑机接口科普0001——脑机接口的概念