动态链接库、HOOK及windows API编程需要注意的地方
2013-04-02 13:10
447 查看
extern “C”的作用:
C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。
1、dll编写(使用默认的C调用约定,也没有用 extern “C”而是用了def文件,而.def文件相当于 extern “C” _declspec(dllexport))
添加一个模块文件Dll.def
可执行文件隐式链接调用dll(需要导入文件)
可执行文件显示加载调用dll(不需要导入库文件)
现在来了解HOOK吧
Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommended; otherwise, other applications that have installed hooks will not receive hook notifications and may behave
incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications.
Before terminating, an application must call the UnhookWindowsHookEx function to free system resources associated with the hook.
网上摘文:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创 建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接 口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并 进行处理。这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。 可见,利用钩子可以实现许多特殊而有用的功能。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得 到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函 数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者 修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加 入的先获得控制权。
Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。
大多数人或者网上文章认为全局钩子都要依赖于一个DLL才能正常工作的,常常会看到很多人在论坛上长期争论一个话题:“全局钩子一定要在DLL里面吗?”。实际上这里有一个概念的问题,究竟上面提到的全局钩子是指什么。通过对上面各种钩子的作用域的理解就会发现这个问题的答案。
上面一共提到了15种钩子,他们的作用域请看下表:
表一:钩子作用域
WH_JOURNALPLAYBACK,WH_JOURNALRECORD,WH_KEYBOARD_LL,WH_MOUSE_LL、WH_SYSMSGFILTER这5种钩子本身的作用域就是全局的,不管钩子是直接写在应用程序的代码里还是放在DLL中,他们都能够钩住系统的消息。剩下的10种钩子,他们的作用域既可以是线程的又可以是全局的,当将相应的钩子直接写在应用程序的代码中时,他们只能捕获当前线程上下文的消息。那么他们如何实现捕获全局消息的功能呢?当把钩子写入到一个单独的DLL中再引用后,系统自动将该DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程,从而达到捕获全局消息的目的。相对来说,前面5种钩子本身就是全局的,是不需要注入的。
因此,对于前面问题的答案就是:要实现捕获全局消息功能的钩子,是否要写在单独的DLL里面,取决于钩子的类型以及相应的作用域。
如果对于同一事件既安装了线程勾子又安装了全局勾子,那么系统会自动先调用线程勾子,然后调用全局勾子。
//hook.cpp
hook.def
windows API编程需要注意的地方
1、阅读API函数说明时,需要认真的去阅读,对于初学者一般不喜欢看return values和remarks部分,但是API函数之间的联系是非常密切的,而后面的return values和remarks也是我们需要去关注的地方,之前看一些朋友编写回调函数的时,因为没有详细的去看相关函数的返回值说明部分,导致编写时出现了很多的问题。
例:
MouseProc
Return Values
If nCode is less than zero, the hook procedure must return the value returned byCallNextHookEx.
If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you callCallNextHookEx and return the value it returns; otherwise, other applications that have installed
WH_MOUSE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.
The hook procedure must not install a JournalPlaybackProc callback function.
C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。
1、dll编写(使用默认的C调用约定,也没有用 extern “C”而是用了def文件,而.def文件相当于 extern “C” _declspec(dllexport))
//Dll.h #ifdef __dect #else #define __dect _declspec(dllexport) #endif __dect int add(int a,int b); __dect int sub(int a,int b);
//dll.cpp #include "Dll.h" int add(int a,int b) { return a+b; } int sub(int a,int b) { return a-b; }
添加一个模块文件Dll.def
LIBRARY Dll EXPORTS add sub
提示:可用#import ,#pragma comment ,LoadLibrary 三种引入dll
可执行文件隐式链接调用dll(需要导入文件)extern int add(int a,int b); extern int sub(int a,int b); //_declspec(dllimport) int add(int a,int b); //_declspec(dllimport) int sub(int a,int b); void CDllTestDlg::OnBtnAdd() { // TODO: Add your control notification handler code here CString str; str.Format("3+5=%d",add(3,5)); MessageBox(str); } void CDllTestDlg::OnBtnSub() { // TODO: Add your control notification handler code here CString str; str.Format("8-5=%d",sub(8,5)); MessageBox(str); }
可执行文件显示加载调用dll(不需要导入库文件)
//extern int add(int a,int b); //extern int sub(int a,int b); //_declspec(dllimport) int add(int a,int b); //_declspec(dllimport) int sub(int a,int b); void CDllTestDlg::OnBtnAdd() { // TODO: Add your control notification handler code here /* CString str; str.Format("3+5=%d",add(3,5)); MessageBox(str); */ HINSTANCE hDll; hDll=LoadLibrary("Dll1.dll"); typedef int (* ADDRPROC)(int a,int b); //ADDRPROC Add=(ADDRPROC)GetProcAddress(hDll,"add"); ADDRPROC Add=(ADDRPROC)GetProcAddress(hDll,MAKEINTRESOURCE(1)); if (!Add) { MessageBox("导出函数失败"); return; } CString str; str.Format("3+5=%d",Add(3,5)); MessageBox(str); FreeLibrary(hDll); } void CDllTestDlg::OnBtnSub() { // TODO: Add your control notification handler code here /* CString str; str.Format("8-5=%d",sub(8,5)); MessageBox(str); */ }
现在来了解HOOK吧
Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommended; otherwise, other applications that have installed hooks will not receive hook notifications and may behave
incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications.
Before terminating, an application must call the UnhookWindowsHookEx function to free system resources associated with the hook.
网上摘文:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创 建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接 口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并 进行处理。这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。 可见,利用钩子可以实现许多特殊而有用的功能。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得 到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函 数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者 修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加 入的先获得控制权。
Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。
大多数人或者网上文章认为全局钩子都要依赖于一个DLL才能正常工作的,常常会看到很多人在论坛上长期争论一个话题:“全局钩子一定要在DLL里面吗?”。实际上这里有一个概念的问题,究竟上面提到的全局钩子是指什么。通过对上面各种钩子的作用域的理解就会发现这个问题的答案。
上面一共提到了15种钩子,他们的作用域请看下表:
Hook | Scope |
WH_CALLWNDPROC | Thread or global |
WH_CALLWNDPROCRET | Thread or global |
WH_CBT | Thread or global |
WH_DEBUG | Thread or global |
WH_FOREGROUNDIDLE | Thread or global |
WH_GETMESSAGE | Thread or global |
WH_JOURNALPLAYBACK | Global only |
WH_JOURNALRECORD | Global only |
WH_KEYBOARD | Thread or global |
WH_KEYBOARD_LL | Global only |
WH_MOUSE | Thread or global |
WH_MOUSE_LL | Global only |
WH_MSGFILTER | Thread or global |
WH_SHELL | Thread or global |
WH_SYSMSGFILTER | Global only |
WH_JOURNALPLAYBACK,WH_JOURNALRECORD,WH_KEYBOARD_LL,WH_MOUSE_LL、WH_SYSMSGFILTER这5种钩子本身的作用域就是全局的,不管钩子是直接写在应用程序的代码里还是放在DLL中,他们都能够钩住系统的消息。剩下的10种钩子,他们的作用域既可以是线程的又可以是全局的,当将相应的钩子直接写在应用程序的代码中时,他们只能捕获当前线程上下文的消息。那么他们如何实现捕获全局消息的功能呢?当把钩子写入到一个单独的DLL中再引用后,系统自动将该DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程,从而达到捕获全局消息的目的。相对来说,前面5种钩子本身就是全局的,是不需要注入的。
因此,对于前面问题的答案就是:要实现捕获全局消息功能的钩子,是否要写在单独的DLL里面,取决于钩子的类型以及相应的作用域。
如果对于同一事件既安装了线程勾子又安装了全局勾子,那么系统会自动先调用线程勾子,然后调用全局勾子。
//hook.cpp
#include <windows.h> HHOOK g_hMouse=NULL; HHOOK g_hKey=NULL; HINSTANCE g_hinst=NULL; #pragma data_seg("mysect") HWND g_hWnd=NULL; #pragma data_seg() // BOOL WINAPI DllMain( HINSTANCE hinstDLL, // handle to the DLL module DWORD fdwReason, // reason for calling function LPVOID lpvReserved // reserved ) { g_hinst=hinstDLL; return TRUE; } 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_ESCAPE==wParam) { ::SendMessage(g_hWnd,WM_CLOSE,0,0); UnhookWindowsHookEx(g_hMouse); UnhookWindowsHookEx(g_hKey); return 1; }else { //return CallNextHookEx(g_hKey,code,wParam,lParam); return 1; } } void setHook(HWND hWnd) { g_hWnd=hWnd; g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("hook"),0); g_hKey=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("hook"),0); }
hook.def
LIBRARY hook EXPORTS setHook SECTIONS mysect read write shared
windows API编程需要注意的地方
1、阅读API函数说明时,需要认真的去阅读,对于初学者一般不喜欢看return values和remarks部分,但是API函数之间的联系是非常密切的,而后面的return values和remarks也是我们需要去关注的地方,之前看一些朋友编写回调函数的时,因为没有详细的去看相关函数的返回值说明部分,导致编写时出现了很多的问题。
例:
MouseProc
Return Values
If nCode is less than zero, the hook procedure must return the value returned byCallNextHookEx.
If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you callCallNextHookEx and return the value it returns; otherwise, other applications that have installed
WH_MOUSE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.
Remarks
An application installs the hook procedure by specifying the WH_MOUSE hook type and a pointer to the hook procedure in a call to theSetWindowsHookEx function.The hook procedure must not install a JournalPlaybackProc callback function.
相关文章推荐
- c 语言的内存分配 需要注意的地方
- struts.xml配置文件中需要注意的地方
- 关于在使用parseInt进行日期判断需要注意的地方
- 26个提升java性能需要注意的地方
- Android组建4:android中需要注意的几个地方
- 用fastjson反序列化时的一个需要注意的地方
- python 爬虫实现前需要注意的地方
- load data infile 需要注意的一些地方
- JQUERY中的getJSON方法需要注意的一个地方:单引号与双引号
- stdlib.h中system函数一定需要注意的地方
- python3.6下安装结巴分词需要注意的地方
- 执行存储过程需要注意的地方
- MySQL的23个需要注意的地方
- link流程 建立时需要注意的地方
- 在Eclipse Java EE中安装 Emmet (Zend Coding) 需要注意的地方!
- Kettle中txt类型数据源作为输入需要注意的地方
- [js高手之路]使用原型对象(prototype)需要注意的地方
- iOS 需要注意的地方
- SharePoint中ListItem更新的一个需要注意的地方
- 从String类看写C++ class需要注意的地方