钩子的概念
钩子机制允许应用程序截获处理window消息或特定事件。与DOS中断截获处理机制有类似之处。钩子(Hook),是Windows消息处理机制的一个平台(point),应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。每一个hook都有一个与之相关联的指针列表,称之为钩子链表,该链表中的指针指向这个钩子的各个处理子程。一个钩子处理一种类型的消息。当钩子所监视的消息出现时,Windows调用链表中的第一个钩子子程。某些类型的钩子只能在系统范围内设置处理子程,其余类型的钩子还可以在特定的线程中设置(用SetWindowsHookEx设置)。对于某一特定类型的钩子(它处理某一类型的消息),线程钩子子程被先调用,接着是系统钩子子程。钩子子程是一个应用程序定义的回调函数(callback function),不能定义成某个类的成员函数,只能定义为普通的C函数。例如:
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam)
钩子的设置
可以使用API函数SetWindowsHookEx()把一个应用程序定义的钩子子程安装到钩子链表中。所安装的钩子子程用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。
HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
或是一个由别的进程创建的线程的标识,lpfn必
须指向DLL中的钩子子程。除此以外,lpfn可以
指向当前进程的一段钩子子程代码。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程
的DLL。如果dwThreadId 标识当前进程创建的一
个线程,而且子程代码位于当前进程,hMod必须
为NULL。
DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符,
如果为0,钩子子程与所有的线程关联。
);
函数成功则返回钩子子程的句柄,失败返回NULL。
以上所说的钩子子程与线程相关联是指在一钩子链表中发给该线程的消息同时发送给钩子子程,且被钩子子程先处理。
虽然这并不是强制的,但一般推荐在钩子子程中调用CallNextHookEx()函数以执行钩子链表所指的下一个钩子子程。否则安装了别的钩子的应用程序就会收不到钩子通知,从而产生错误的结果。除非确实需要禁止向别的应用程序发通知,否则应调用CallNextHookEx()。程序终止之前,必须调用UnhookWindowsHookEx()函数释放钩子关联的系统资源。
钩子的实例
//找到要截获其消息的窗口的句柄
HWND hWnd=::FindWindow(
"#32770",//LPCTSTR lpClassName,
NULL //LPCTSTR lpWindowName
);
if(hWnd) //如果窗口句柄非零,则设置钩子,
HHOOK oldkeyhook=SetWindowsHookEx(
WH_KEYBOARD, //截获键盘消息的钩子类型
(HOOKPROC)KeyBoardProc, //钩子子程地址
//包含钩子子程的动态链接库的地址
GetModuleHandle("hookdll.dll"),
//得到创建该窗口的线程的标识
GetWindowThreadProcessId(hWnd,NULL));
释放钩子函数的资源:
UnhookWindowsHookEx(oldkeyhook);
钩子消息处理函数:
建议在动态链接库中实现钩子消息处理函数,这样比较不容易犯错误。
下面是钩子消息处理函数的例子:
LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//当接收到的消息为WM_KEYUPSH时,存储字符到文件log.sys中
if(lParam&0x80000000)
{
char code=(char)wParam;
CFile
file("c:/log.sys",CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite);
file.SeekToEnd();
file.Write(&code,1);
file.Close();
}
//调用CallNextHookEx()函数,并返回该函数的返回值。
return CallNextHookEx(oldkeyhook, nCode, wParam, lParam);
}
钩子机制允许应用程序截获处理window消息或特定事件。与DOS中断截获处理机制有类似之处。钩子(Hook),是Windows消息处理机制的一个平台(point),应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。每一个hook都有一个与之相关联的指针列表,称之为钩子链表,该链表中的指针指向这个钩子的各个处理子程。一个钩子处理一种类型的消息。当钩子所监视的消息出现时,Windows调用链表中的第一个钩子子程。某些类型的钩子只能在系统范围内设置处理子程,其余类型的钩子还可以在特定的线程中设置(用SetWindowsHookEx设置)。对于某一特定类型的钩子(它处理某一类型的消息),线程钩子子程被先调用,接着是系统钩子子程。钩子子程是一个应用程序定义的回调函数(callback function),不能定义成某个类的成员函数,只能定义为普通的C函数。例如:
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam)
钩子的设置
可以使用API函数SetWindowsHookEx()把一个应用程序定义的钩子子程安装到钩子链表中。所安装的钩子子程用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。
HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
或是一个由别的进程创建的线程的标识,lpfn必
须指向DLL中的钩子子程。除此以外,lpfn可以
指向当前进程的一段钩子子程代码。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程
的DLL。如果dwThreadId 标识当前进程创建的一
个线程,而且子程代码位于当前进程,hMod必须
为NULL。
DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符,
如果为0,钩子子程与所有的线程关联。
);
函数成功则返回钩子子程的句柄,失败返回NULL。
以上所说的钩子子程与线程相关联是指在一钩子链表中发给该线程的消息同时发送给钩子子程,且被钩子子程先处理。
虽然这并不是强制的,但一般推荐在钩子子程中调用CallNextHookEx()函数以执行钩子链表所指的下一个钩子子程。否则安装了别的钩子的应用程序就会收不到钩子通知,从而产生错误的结果。除非确实需要禁止向别的应用程序发通知,否则应调用CallNextHookEx()。程序终止之前,必须调用UnhookWindowsHookEx()函数释放钩子关联的系统资源。
钩子的实例
//找到要截获其消息的窗口的句柄
HWND hWnd=::FindWindow(
"#32770",//LPCTSTR lpClassName,
NULL //LPCTSTR lpWindowName
);
if(hWnd) //如果窗口句柄非零,则设置钩子,
HHOOK oldkeyhook=SetWindowsHookEx(
WH_KEYBOARD, //截获键盘消息的钩子类型
(HOOKPROC)KeyBoardProc, //钩子子程地址
//包含钩子子程的动态链接库的地址
GetModuleHandle("hookdll.dll"),
//得到创建该窗口的线程的标识
GetWindowThreadProcessId(hWnd,NULL));
释放钩子函数的资源:
UnhookWindowsHookEx(oldkeyhook);
钩子消息处理函数:
建议在动态链接库中实现钩子消息处理函数,这样比较不容易犯错误。
下面是钩子消息处理函数的例子:
LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//当接收到的消息为WM_KEYUPSH时,存储字符到文件log.sys中
if(lParam&0x80000000)
{
char code=(char)wParam;
CFile
file("c:/log.sys",CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite);
file.SeekToEnd();
file.Write(&code,1);
file.Close();
}
//调用CallNextHookEx()函数,并返回该函数的返回值。
return CallNextHookEx(oldkeyhook, nCode, wParam, lParam);
}