消息钩子与定时器(VC_Win32)
目录
(本章节中例子都是用 VS2005 编译调试的)
消息钩子
概述
钩子过程
操作系统在传递消息时,将我们感兴趣的消息先传递给HOOK过程,在此函数中进行检查,然后在决定是否放行该消息,就好像逃犯在逃亡时可能会经过许多段路段,为了抓住他,警察要在某些地方设置检查站,以便检查过往的车辆和行人,我们可以把车辆和行人看做是消息,检查站就好像是HOOK过程,如果在摸个检查站发现了这个逃犯,就会把他抓起来,这样就相当于阻止了逃犯的逃亡过程,让他无法在继续逃亡下去了,这个道理和钩子过程是一样的,操作系统将我们感兴趣的消息都交给钩子过程,后者实际就是一个函数,在此函数中进行判断,如果是我们希望屏蔽的消息,那么就直接处理掉,不然它继续向下传递.如果我们不感兴趣的消息,就直接放弃对它们的处理,这就好像对于那些不是逃犯的行人和车辆一样,警察会让他们继续前进
钩子链
SetWindowsHookEx函数作用是安装一个应用程序定义的钩子过程,并将其放到钩子链中,为了让读者更好的理解钩子的概念,让我们在看看前面所举的逃犯的例子.警察在抓捕逃犯时,可以再多个地方设置检查站,逐一对车辆和行人进行排查,同样地,应用程序也可以在多个地方安装钩子函数,对我们感兴趣的多个消息逐一进行排查,这样多个钩子过程就形成了钩子链,要注意的是,最后安装的钩子过程总是排列在该链的前面
消息钩子分类
- 进程内钩子 勾取本进程消息
- 全局钩子 勾取所有消息
相关函数
函数原型
HHOOK SetWindowsHookEx( int idHook, // hook type HOOKPROC lpfn, // hook procedure HINSTANCE hMod, // handle to application instance DWORD dwThreadId // thread identifier );
参数说明
- idHook
指定要安装的钩子过程的类型
- WH_CALLWNDPROC 安装一个钩子过程,在操作系统将消息发送到目标窗口处理过程之前,对该消息进行监视
- WH_CALLWNDPROCRET 安装一个钩子过程,它对被目标窗口处理过了的消息进行监视
- WH_CBT 安装一个钩子过程,接受对CBT应用程序有用的消息
- WH_DEBUG 安装一个钩子过程,以便对其他钩子过程调试
- WH_FOREGROUNDIDLE 安装一个钩子过程,该钩子过程当应用程序的前提线程即将进入空闲状态时被调用,它有助于在空闲时间内执行低优先级的任务
- WH_GETMESSAGE 安装一个钩子过程对发送到消息队列的消息进行监视
- WH_JOURNALPLAYBACK 安装一个钩子过程,对此前由WH_JORNALRECORD钩子过程记录的消息进行发送
- WH_JOURNALRECORD 安装一个钩子过程,对发送到系统消息队列的输入消息进行记录
- WH_KEYBOARD 安装一个钩子过程,对键盘按键消息进行监视
- WH_KEYBOARD_LL 安装一个钩子过程,只能在Windows NT中安装,用来对底层的键盘输入事件进行监视
- WH_MOUSE 安装一个钩子过程,对鼠标消息进行监视
- WH_MOUSE_LL 安装一个钩子过程,只能在Windows NT中安装,用来对底层的鼠标输入事件进行监视
- WH_MSGFILTER 安装一个钩子过程,以监视由对话框,消息框,菜单条,或滚动条中输入事件引发的消息
- WH_SHELL 安装一个钩子过程,以接受外壳应用程序有用的通知
- WH_SYSMSGFILTER 安装一个钩子过程,以监视对话框,消息框,菜单条,或滚动条中输入事件引发的消息,该钩子过程对系统中所有应用程序的这里消息都进行监视
对应的回调函数也就是钩子函数的处理过程的形式在MSDN查阅
如果钩子函数返回非零值,表示已经对当前消息进行了处理,这样系统就不会在将这个消息传递给目标窗口过程,因此,如果钩子过程对于当前消息进行处理,则返回一个非零值,以避免系统再次将此消息传递给目标窗口过程;否则建议调用CallNextHookEx含返回该函数的返回值,以便其他安装了此消息类型钩子过程的应用程序捕获相应的通知
- lpfn
指向相应的钩子过程,如果dwThreadId参数为0,或者指定了一个其他进程创建的线程标识符,那么参数lpfn必须指向一个位于动态链接库中的钩子过程.否则,参数lpfn可以指向当前进程相关的代码中定义的一个钩子过程
- hMod
指定lpfn指向的钩子过程所在的DLL的句柄,如果参数dwThreadId指定的线程由当前进程穿件,并且相应的钩子过程定义与当前进程相关的代码中,那么必须将参数hMod设置为NULL(全局钩子,此参数必须指向DLL句柄)
- dwThreadId
指定与钩子过程相关的线程标识,如果值为0,那么按照的钩子过程将与桌面上运行的所有线程都有关(安装的钩子过程可以与某个特定线程相关,也可以和所有线程相关,取决于这个参数的取值)
返回值
如果成功返回的值是钩子过程的句柄,如果函数失败返回的是NULL
函数原型
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 );
参数说明
- hhk: 指定当前钩子过程句柄
- nCode,wParam,lParam: 后三个参数是钩子过程回调函数的三个参数
返回值
这个值是在钩子链中的下个钩子函数的返回值
函数原型
BOOL UnhookWindowsHookEx( HHOOK hhk // handle to hook procedure );
参数说明
- hhk: 要被移除的消息钩子
编写消息钩子
流程图:
- 进程钩子
- 全局钩子
代码样例:
进程钩子
程序源码:
#include<windows.h> #include<string.h> HHOOK g_hKeyboard=NULL; HHOOK g_hMouse=NULL; LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam // mouse coordinates ) { return 1; } LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ) { //当按下回车键时候取消消息钩子 if(VK_RETURN==wParam) { UnhookWindowsHookEx(g_hKeyboard); UnhookWindowsHookEx(g_hMouse); MessageBox(NULL,"取消消息钩子","消息",MB_OK); } return 1; } LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // pointer to command line int nCmdShow // show state of window ) { WNDCLASS wndclass; MSG msg; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); wndclass.hInstance=hInstance; wndclass.lpfnWndProc=textprom; wndclass.lpszClassName="text"; wndclass.lpszMenuName=NULL; wndclass.style=CS_HREDRAW | CS_VREDRAW; if(!RegisterClass(&wndclass)) { MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP); } HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, 400,250,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); //设置鼠标和键盘消息钩子 g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId()); g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,GetCurrentThreadId()); while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); break; default: ; } return DefWindowProc(hwnd,uMsg,wParam,lParam); }
运行结果:
全局钩子
动态链接库源码:
// .h 头文件 ----------------------------------------------------- #ifndef DLL_API #define DLL_API _declspec(dllimport) #endif #include"windows.h" HHOOK g_hMouse=NULL; HHOOK g_hKeyboard=NULL; DLL_API void SetHook(); LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam, LPARAM lParam); LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam,LPARAM lParam); // .cpp 源程序 --------------------------------------------------- #define DLL_API _declspec(dllexport) #include"dllHook.h" LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam // mouse coordinates ) { return 1; } LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ) { if(VK_RETURN==wParam) { UnhookWindowsHookEx(g_hMouse); UnhookWindowsHookEx(g_hKeyboard); MessageBox(NULL,"取消消息钩子","消息",MB_OK); } return 1; } void SetHook() { g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("dllHook.dll"),0); g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("dllHook.dll"),0); }
程序源码:
#include<windows.h> //加载动态连接库头文件 #include"../dllHook/dllHook.h" //加载动态连接库的引入库(LIB) #pragma comment(lib, "../debug/dllHook.lib") LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // pointer to command line int nCmdShow // show state of window ) { WNDCLASS wndclass; MSG msg; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); wndclass.hInstance=hInstance; wndclass.lpfnWndProc=textprom; wndclass.lpszClassName="text"; wndclass.lpszMenuName=NULL; wndclass.style=CS_HREDRAW | CS_VREDRAW; if(!RegisterClass(&wndclass)) { MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP); } HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, 400,250,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch(uMsg) { case WM_LBUTTONDOWN: //设置消息钩子 SetHook(); break; case WM_DESTROY: PostQuitMessage(0); break; default: ; } return DefWindowProc(hwnd,uMsg,wParam,lParam); }
运行结果(回车钱所有鼠标事件和键盘事件都将被屏蔽)
定时器
相关函数
函数原型:
UINT SetTimer(
HWND hWnd,
UINT nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc );
参数说明:
- hWnd: 指定定时器的关联窗口
- nIDEvent: 指定了不为零的定时器标识符.
- nElapse: 指定了定时值;以毫秒为单位.
- lpfnTimer: 指定了应用程序提供的TimerProc回调函数的地址,该函数被用于处理WM_TIMER消息.如果这个参数为NULL,则WM_TIMER消息被放入应用程序的消息队列并由CWnd对象来处理.
返回值
如果函数成功,则返回新定时器的标识符.应用程序可以将这个值传递给KillTimer成员函数以销毁定时器.如果成功,则返回非零值;否则返回0
说明:
- 所属类 CWnd
- 相对事件 WM_TIMER
- 这个函数设置一个系统定时器.指定了一个定时值,每当发生超时,则系统就向设置定时器的应用程序的消息队列发送一个WM_TIMER消息,或者将消息传递给应用程序定义的TimerProc回调函数.lpfnTimer回调函数不需要被命名为TimerProc,但是它必须按照如下方式定义:
void CALLBACK EXPORT TimerProc( HWND hWnd, // 调用SetTimer的窗口的句柄 UINT nMsg, // WM_TIMER UINT nIDEvent // 定时器标识 DWORD dwTime // 系统时间 );
函数原型
BOOL KillTimer( int nIDEvent );
参数说明
- nIDEvent: 传递给SetTimer的定时器事件值
返回值
指定了函数的结果.如果事件已经被销毁,则返回值为非零值.如果KillTimer成员函数不能找到指定的定时器事件,则返回0
说明
- 所属类 CWnd
- 销毁以前调用SetTimer创建的用nIDEvent标识的定时器事件.任何与此定时器有关的未处理的WM_TIMER消息都从消息队列中清除
编写定时器
流程图:
代码样例:
程序源码:
#include"windows.h" #include<cstdlib> #include<iostream> using namespace std; VOID CALLBACK TimerProc(HWND hwnd,UINT msg ,UINT_PTR dwEvent,DWORD dwTime); void main() { MSG msg; //建立定时器 UINT TimerID = SetTimer(NULL,1,1000,(TIMERPROC)TimerProc); //消息循环 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } system("pause"); } VOID CALLBACK TimerProc(HWND hwnd,UINT msg ,UINT_PTR dwEvent,DWORD dwTime) { cout<<"定时器消息回调函数调用成功"<<endl; //关闭定时器 if(KillTimer(NULL,dwEvent)) PostQuitMessage(0); }
运行结果: