动态链接库、HOOK及windows API编程需要注意的地方

extern “C”的作用:

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. 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值