Windows平台上消息处理技术浅析

2012-04-08 13:35谢智明
湖南科技学院学报 2012年8期
关键词:句柄右键线程

谢智明

(湖南科技学院 计算机与通信工程系,湖南 永州 425100)

Windows平台上消息处理技术浅析

谢智明

(湖南科技学院 计算机与通信工程系,湖南 永州 425100)

本文介绍了在Windows平台上获取消息并进行处理的技术,举例说明了如何编写消息处理机制应用程序的步骤与方法。

hook;消息获取

1 hook机制

Windows系统建立在事件驱动的机制上,也就是整个系统都是通过消息的传递来实现的。 hook机制是一种特殊的消息处理机制,可以监视系统或进程中的各种事件消息,获取发往目标窗口的消息并进行处理。这样,我们就可以在系统中安装自定义的hook,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。hook的种类很多,每种hook可以截获并处理相应的消息,如键盘hook可以截获键盘消息,外壳 hook可以截取、启动和关闭应用程序的消息等。hook可以分为线程hook和系统hook, 线程hook监视指定线程的事件消息, 系统hook监视系统中的所有线程的事件消息。因为系统hook会影响系统中所有的应用程序,所以hook函数必须放在独立的动态链接库(DLL) 中。

2 实现hook机制的关键技术

2.1 windows的hook程序,需要用到几个sdk中的api函数

下面列出这几个函数的原型及说明:hhook setwindowshookex(int idhook,hook_proc lpfn,hinstance hmod,dword dwthreadid);

参数说明如下:

idhook:hook的类型

lpfn:hook处理函数地址

hmod:包含hook函数的模块句柄

dwthreadid:hook的监控线程

函数说明:函数将在系统中挂上一个由idhook指定类型的hook,监控并处理相应的特定消息。bool unhookwindowshookex(hhook hhk);

函数说明:函数将撤销由hhk指定的hook。lresult callnexthookex( hhook hhk, int ncode,wparam wparam,lparam lparam );

函数说明:函数将消息向下传递,下一个hook处理将截获这一消息。

2.2 由于hook的处理涉及到模块及进程间的数据地址问题,一般情况是把hook整合到一个动态链接库(dll)中,VC中有三种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MFC DLL(扩展MFC DLL)。

第一种DLL在编译时把使用的MFC代码链接到DLL中,执行程序时不需要其他MFC动态链接类库的支持,但体积较大。

第二种DLL在运行时动态链接到MFC类库,因而体积较小,但却依赖于MFC动态链接类库的支持;这两种DLL均可被MFC程序和Win32程序使用。

第三种DLL的也是动态连接,但做为MFC类库的扩展,只能被MFC程序使用。

另外,要设立一个全局数据共享数据段,以存贮一些全局变量,保留上次hook消息事件发生时的状态。

2.3 Win32 DLL的入口和出口函数都是DLLMain。只要有进程或线程载入和卸载DLL时,都会调用该函数,其原型是:

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved); 其中,第一个参数表示DLL的实例句柄;第三个参数系统保留;第二个参数指明了当前调用该动态连接库的状态,它有四个可能的值:DLL_PROCESS_ATTACH(进程载入)、DLL_THREAD_ATTACH(线程载入)、DLL_THREAD_DETACH(线程卸载)、DLL_PROCESS_DETACH(进程卸载)。在DLLMain函数中可以通过对传递进来的这个参数的值进行判别,根据不同的参数值对DLL进行必要的初始化或清理工作。由于在Win32环境下,所有进程的空间都是相互独立的,这减少了应用程序间的相互影响,但大大增加了编程的难度。当进程在动态加载DLL时,系统自动把DLL地址映射到该进程的私有空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间,每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。当DLL内存被映射到进程空间中,每个进程都有自己的全局内存拷贝,加载DLL的每一个新的进程都重新初始化这一内存区域,也就是说进程不能再共享DLL。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。一种方法便是把这些需要共享的数据单独分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,建立一个内存共享的DLL。

3 编写消息处理机制应用程序的步骤与方法

建立用hook机制实现截获鼠标左右键按压次数的应用程序, 建立hook程序时需要把hook处理整合到动态链接库中,所以例程中需要建立两个project。

3.1 hook处理动态链接库

1、选择mfc appwizard(dll)创建一个新project,命名为“GetNumberOfMouse”。

2、选择mfc extension dll类型。

3、创建一个新的头文件,命名为“hook.h”,修改它的代码如下:

extern "C" LRESULT CALLBACK mouseproc(int code,WPARAM wparam,LPARAM lparam); //hook处理函数

extern "C" bool WINAPI starthook(); //启动hook函数

extern "C" bool WINAPI stophook(); //撤销hook函数

extern "C" int WINAPI getresultl(); //取得鼠标左键单击次数的函数

extern "C" int WINAPI getresultr(); //取得鼠标右键单击次数的函数

4、修改GetNumberOfMouse.cpp程序代码如下:

#include "hook.h" //包含头文件hook

#pragma data_seg("publicdata") //定义全局数据段

HHOOK hhook=NULL; //hook句柄

HINSTANCE pinstance=NULL;//hook模块句柄

UINT mouseclickl=0; //记录鼠标左键单击次数的变量

UINT mouseclickr=0;//记录鼠标右键单击次数

#pragma data_seg()

extern "C" int APIENTRY

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

{ if (dwReason == DLL_PROCESS_ATTACH)

{…… //省略部分机器生成代码

new CDynLinkLibrary(SpyDLL);

pinstance=hInstance;//取得模块句柄

}……;

}

extern "C" LRESULT CALLBACK mouseproc(int code,WPARAM wparam,LPARAM lparam) //hook处理函

{

if (code<0) //若code〈0,则直接调用callnexthookex返回

return CallNextHookEx(hhook, code, wparam, lparam);

if(wparam==WM_LBUTTONDOWN)

{ mouseclickl++;//记录鼠标左键单击次数 }

if(wparam==WM_RBUTTONDOWN)

{ mouseclickr++;//记录鼠标右键单击次数 }

return CallNextHookEx(hhook, code, wparam,lparam);

}

extern "C" bool WINAPI starthook()//启动hook函数

{

hhook=SetWindowsHookEx(WH_MOUSE,mouseproc,pinstance,0);//挂上hook

if(hhook!=NULL)

return true;

else return false;

}

extern "C" bool WINAPI stophook() //撤销hook函数

{ return UnhookWindowsHookEx(hhook); //撤销hook}

extern "C" int WINAPI getresultl()//返回鼠标左键单击次数

{ return mouseclickl;}

extern "C" int WINAPI getresultr()//返回鼠标右键单击次数

{ return mouseclickr;}

5、 修改GetNumberOfMouse.def程序代码如下:

exports

stophook @2

starthook @1

getresultl @3

getresultr @4

6、编译project,生成GetNumberOfMouse.dll文件和GetNumberOfMouse.lib文件。

3.2 建立使用hook的应用程序

1、生成一个单文档的可执行文件(exe)的project。

2、 修改资源中的主选单,增加一个选单项“监控”,下有三个子选单项,分别为“启动”、“撤销”和“取出”。

3、在project中加入GetNumberOfMouse.lib文件。

4、分别修改“启动”、“撤销”和“取出”选单项的command响应函数如下:

#include "E:DevStudioMyProjectsGetNumberOfMousehook.h" //路径可不同

void CMainFrame::OnMenuitem32771() //“启动”选单项的响应函数

{ starthook(); }

void CMainFrame::OnMenuitem32772() //“撤销”选单项的响应函数

{ stophook();}

void CMainFrame::OnMenuitem32773() //“取出”选单项的响应函数

{ int resultl=getresultl();

int resultr=getresultr();

char buffer[80];

wsprintf(buffer,"在程序运行期间,你共单击鼠标左键%d次,右键%d次!",resultl,resultr);

::MessageBox(this->m_hWnd,buffer,"message",MB_OK);

}

编译这个project,并把GetNumberOfMouse.dll放到生成的可执行文件目录下,便可运行程序。运行时,选择“监控”选单中的“启动”选单项,hook便开始工作,监视鼠标的活动情况;选择“撤销”选单项,系统便撤销hook;选择“取出”选单项,程序便报告在监控期间,用户分别单击鼠标左键和右键的次数。以上程序在windows xp,visual c++ 6.0环境下成功运行。

[1]汤春林,等.windows程序设计与架构[M].北京:电子工业出版社,2011.

[2]Warton,Java多线程编程初步[Z].电脑报,2004-4-10.

[3]毛德操.Windows内核情景分析[M].北京:电子工业出版社,2009.

TP39

A

1673-2219(2012)08-0046-03

2012-03-20

谢智明(1971-),湖南永州人,计算机软件与技术系统分析师,研究方向为计算机及应用。

(责任编校:何俊华)

猜你喜欢
句柄右键线程
基于C#线程实验探究
轻松整理Win10右键菜单
自定义“开始”右键控制菜单
基于国产化环境的线程池模型研究与实现
用右键菜单管理右键菜单
高校图书馆持久标识符应用研究
编译程序语法分析句柄问题分析与探讨
浅谈linux多线程协作
给Windows 10右键菜单做“手术”
Java的多线程技术探讨