数学与计算机学院
《计算机接口技术 》
专 业:班 级:学 号:姓 名:指导老师:实验报告
网络工程 1201 1205110108 王振京 郭峰林
实验3 基于DLL 与HOOK 技术的键盘消息拦截与读音
一 实验目的
1.了解MFC DLL动态连接库的编程方法; 2.了解HOOK 技术和回调函数的运行机制; 3.学习MFC 中加载动态连接库的方法。 二 实验指导
1.HOOK 的基本概念
在Windows 下,当硬件或软件产生中断时,系统会发送一个消息给用户程序。因此,用户程序一般不使用中断,而是采用拦截系统消息的方法。为了拦截不属于本应用程序的消息,拦截程序必须得到系统的认可,由系统安装成全局运行。
HOOK 即通常所说的钩子。实际上,HOOK 就是上面所说的消息拦截程序段。通过系统调用,把它挂入系统。每当HOOK 所希望的消息发出,在没有到达目的窗口前,HOOK 程序就先捕获该消息,得到控制权。HOOK 程序先处理该消息,再向系统传递该消息。也可以丢弃该消息。系统维护着一个HOOK 链,最近安装的HOOK 总放在链的开始,从而得到优先执行。
2.HOOK 函数的形式及其安装方法
HOOK 函数在程序中应为全局函数,即:HOOK 函数不应写在一个类中。
HOOK 函数是一个消息响应函数,由系统调用,应以回调函数的形式出现,其格式为: LRESULT _declspec(dllexport)_stdcall CALLBACK KeyboardProc( int nCode, // 若为HC_ACTION,说明后两参数含有击键的消息 WPARAM wParam, //虚键码
LPARAM lParam //击键的有关信息,如重复次数等 )
写好HOOK 函数后,应进行安装,才能得到系统的回调。安装HOOK 的函数为: HHOOK SetWindowsHookEx(
int idHook, //钩子的类型,按键为 WH_KEYBOARD HOOKPROC lpfn, //钩子函数的地址 HINSTANCE hMod, //包含钩子函数的模块句柄
DWORD dwThreadId //指定监视的线程。若为NULL ,则为全局钩子 );
3.程序要求
(1)编写含有按键HOOK 的DLL ,要求当按键时,能读出按键名称 (2)编写安装DLL 的应用程序。 三 实验步骤
1.建立DLL
(1)启动VC++,选 File\New
(2)进入MFC AppWizard _ step 1 of 1 (3)在KeyHook.cpp 文件中添加代码:
#include "stdafx.h" #include "KeyHook.h" #include "mmsystem.h" #ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#pragma data_seg(".SHARDAT")
static HHOOK hkb=NULL; //定义HOOK 句柄
#pragma data_seg()
HINSTANCE hInst; //定义本实例的句柄
BOOL __declspec(dllexport)__stdcall installhook() {
hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInst,0); return TRUE; }
BOOL __declspec(dllexport) UnHook() { BOOL
unhooked
=
UnhookWindowsHookEx(hkb); return unhooked; } LRESULT
__declspec(dllexport)__stdcall CALLBACK KeyboardProc(int
nCode,
WPARAM wParam, LPARAM lParam) {
if(((DWORD)lParam&0x40000000) &&
(HC_ACTION==nCode)) { if(wParam>='A' && wParam
KeyName[20],temp[10];
strcpy(KeyName,"sound\\");
在keypress.cpp 添加如下文件:
#include "stdafx.h" #include "KeyPress.h" #include "KeyPressDlg.h" #ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
class CAboutDlg : public CDialog { public: CAboutDlg();
enum { IDD = IDD_ABOUTBOX }; protected: virtual
void
DoDataExchange(CDataExchange* pDX);
temp[0]=wParam; temp[1]=0; strcat(KeyName,temp); strcat(KeyName,".wav");
sndPlaySound(KeyName,SND_ASYNC);
}
}
LRESULT RetVal = CallNextHookEx( hkb, nCode, wParam, lParam ); return(RetVal);}
BEGIN_MESSAGE_MAP(CKeyHookApp, CWinApp)
END_MESSAGE_MAP()
CKeyHookApp::CKeyHookApp(){} CKeyHookApp theApp;
CKeyHookApp::InitInstance() {
AFX_MANAGE_STATE(AfxGetStaticModuleState());
hInst=AfxGetInstanceHandle();
return CWinApp::InitInstance(); }
int CKeyHookApp::ExitInstance() {
UnHook();
return CWinApp::ExitInstance(); }
protected:
DECLARE_MESSAGE_MAP() };
CAboutDlg::CAboutDlg() :
CDialog(CAboutDlg::IDD){} void
CAboutDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP()
CKeyPressDlg::CKeyPressDlg(CWnd* pParent /*=NULL*/) :
CDialog(CKeyPressDlg::IDD,
pParent) {
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void
CKeyPressDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CKeyPressDlg, CDialog)
ON_WM_SYSCOMMAND() ON_WM_PAINT()
ON_WM_QUERYDRAGICON() END_MESSAGE_MAP()
BOOL CKeyPressDlg::OnInitDialog() {
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX
pSysMenu
=
GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBO
X); if (!strAboutMenu.IsEmpty()) {
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); }
}
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set
small icon
static HINSTANCE hinstDLL; BOOL (CALLBACK *inshook)();
if(hinstDLL=LoadLibrary((LPCTSTR)"keyhook.dll")) {
inshook=GetProcAddress(hinstDLL, "installhook"); inshook(); }
return TRUE; // return TRUE unless you set the focus to a control }
void CKeyPressDlg::OnSysCommand(UINT nID, LPARAM lParam) {
if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal();
} else { CDialog::OnSysCommand(nID,
lParam);
} }
void CKeyPressDlg::OnPaint() {
if (IsIconic()) { CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); int cxIcon = GetSystemMetrics(SM_CXICON); int
cyIcon
=
GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x,
y,
m_hIcon);
} else
{ } } HCURSOR
CKeyPressDlg::OnQueryDragIcon() {
return (HCURSOR) m_hIcon; }
CDialog::OnPaint();
四,实验结果:
五,实验总结:
本次实验室关于MFC.DLL 动态链接库的编程方法, 需要了解键盘钩子和相应回调函数的运行机制, 了解DLL 的可重要特性等. 受益颇深.
数学与计算机学院
《计算机接口技术 》
专 业:班 级:学 号:姓 名:指导老师:实验报告
网络工程 1201 1205110108 王振京 郭峰林
实验3 基于DLL 与HOOK 技术的键盘消息拦截与读音
一 实验目的
1.了解MFC DLL动态连接库的编程方法; 2.了解HOOK 技术和回调函数的运行机制; 3.学习MFC 中加载动态连接库的方法。 二 实验指导
1.HOOK 的基本概念
在Windows 下,当硬件或软件产生中断时,系统会发送一个消息给用户程序。因此,用户程序一般不使用中断,而是采用拦截系统消息的方法。为了拦截不属于本应用程序的消息,拦截程序必须得到系统的认可,由系统安装成全局运行。
HOOK 即通常所说的钩子。实际上,HOOK 就是上面所说的消息拦截程序段。通过系统调用,把它挂入系统。每当HOOK 所希望的消息发出,在没有到达目的窗口前,HOOK 程序就先捕获该消息,得到控制权。HOOK 程序先处理该消息,再向系统传递该消息。也可以丢弃该消息。系统维护着一个HOOK 链,最近安装的HOOK 总放在链的开始,从而得到优先执行。
2.HOOK 函数的形式及其安装方法
HOOK 函数在程序中应为全局函数,即:HOOK 函数不应写在一个类中。
HOOK 函数是一个消息响应函数,由系统调用,应以回调函数的形式出现,其格式为: LRESULT _declspec(dllexport)_stdcall CALLBACK KeyboardProc( int nCode, // 若为HC_ACTION,说明后两参数含有击键的消息 WPARAM wParam, //虚键码
LPARAM lParam //击键的有关信息,如重复次数等 )
写好HOOK 函数后,应进行安装,才能得到系统的回调。安装HOOK 的函数为: HHOOK SetWindowsHookEx(
int idHook, //钩子的类型,按键为 WH_KEYBOARD HOOKPROC lpfn, //钩子函数的地址 HINSTANCE hMod, //包含钩子函数的模块句柄
DWORD dwThreadId //指定监视的线程。若为NULL ,则为全局钩子 );
3.程序要求
(1)编写含有按键HOOK 的DLL ,要求当按键时,能读出按键名称 (2)编写安装DLL 的应用程序。 三 实验步骤
1.建立DLL
(1)启动VC++,选 File\New
(2)进入MFC AppWizard _ step 1 of 1 (3)在KeyHook.cpp 文件中添加代码:
#include "stdafx.h" #include "KeyHook.h" #include "mmsystem.h" #ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#pragma data_seg(".SHARDAT")
static HHOOK hkb=NULL; //定义HOOK 句柄
#pragma data_seg()
HINSTANCE hInst; //定义本实例的句柄
BOOL __declspec(dllexport)__stdcall installhook() {
hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInst,0); return TRUE; }
BOOL __declspec(dllexport) UnHook() { BOOL
unhooked
=
UnhookWindowsHookEx(hkb); return unhooked; } LRESULT
__declspec(dllexport)__stdcall CALLBACK KeyboardProc(int
nCode,
WPARAM wParam, LPARAM lParam) {
if(((DWORD)lParam&0x40000000) &&
(HC_ACTION==nCode)) { if(wParam>='A' && wParam
KeyName[20],temp[10];
strcpy(KeyName,"sound\\");
在keypress.cpp 添加如下文件:
#include "stdafx.h" #include "KeyPress.h" #include "KeyPressDlg.h" #ifdef _DEBUG
#define new DEBUG_NEW #undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
class CAboutDlg : public CDialog { public: CAboutDlg();
enum { IDD = IDD_ABOUTBOX }; protected: virtual
void
DoDataExchange(CDataExchange* pDX);
temp[0]=wParam; temp[1]=0; strcat(KeyName,temp); strcat(KeyName,".wav");
sndPlaySound(KeyName,SND_ASYNC);
}
}
LRESULT RetVal = CallNextHookEx( hkb, nCode, wParam, lParam ); return(RetVal);}
BEGIN_MESSAGE_MAP(CKeyHookApp, CWinApp)
END_MESSAGE_MAP()
CKeyHookApp::CKeyHookApp(){} CKeyHookApp theApp;
CKeyHookApp::InitInstance() {
AFX_MANAGE_STATE(AfxGetStaticModuleState());
hInst=AfxGetInstanceHandle();
return CWinApp::InitInstance(); }
int CKeyHookApp::ExitInstance() {
UnHook();
return CWinApp::ExitInstance(); }
protected:
DECLARE_MESSAGE_MAP() };
CAboutDlg::CAboutDlg() :
CDialog(CAboutDlg::IDD){} void
CAboutDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP()
CKeyPressDlg::CKeyPressDlg(CWnd* pParent /*=NULL*/) :
CDialog(CKeyPressDlg::IDD,
pParent) {
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void
CKeyPressDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CKeyPressDlg, CDialog)
ON_WM_SYSCOMMAND() ON_WM_PAINT()
ON_WM_QUERYDRAGICON() END_MESSAGE_MAP()
BOOL CKeyPressDlg::OnInitDialog() {
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX
pSysMenu
=
GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBO
X); if (!strAboutMenu.IsEmpty()) {
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); }
}
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set
small icon
static HINSTANCE hinstDLL; BOOL (CALLBACK *inshook)();
if(hinstDLL=LoadLibrary((LPCTSTR)"keyhook.dll")) {
inshook=GetProcAddress(hinstDLL, "installhook"); inshook(); }
return TRUE; // return TRUE unless you set the focus to a control }
void CKeyPressDlg::OnSysCommand(UINT nID, LPARAM lParam) {
if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal();
} else { CDialog::OnSysCommand(nID,
lParam);
} }
void CKeyPressDlg::OnPaint() {
if (IsIconic()) { CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); int cxIcon = GetSystemMetrics(SM_CXICON); int
cyIcon
=
GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x,
y,
m_hIcon);
} else
{ } } HCURSOR
CKeyPressDlg::OnQueryDragIcon() {
return (HCURSOR) m_hIcon; }
CDialog::OnPaint();
四,实验结果:
五,实验总结:
本次实验室关于MFC.DLL 动态链接库的编程方法, 需要了解键盘钩子和相应回调函数的运行机制, 了解DLL 的可重要特性等. 受益颇深.