一个系统鼠标钩子dll中如何接收应用程序发给它的消息,
我建了一个系统鼠标钩子,它包含在一个dll中,现在我的这个dll中想处理我的应用程序发给它的消息,请问应该如何做,我听说有两种方法,但都对他们有疑问:
1。是在dll中创建一个隐藏窗口,然后在窗口函数中处理消息。
//对此我两个疑问:1。这样创建隐藏窗口会不会消耗太多的资源呢?2。用sendmessage不是需要窗口的句柄吗,那又是应该如何获得这隐藏窗口的句柄呢?
2。使用线程处理消息。
//对这个我就不熟了,我想知道如果建立线程消息处理函数之后会不会让我的鼠标钩子接受不到鼠标消息呢?
请各位大侠帮帮忙?说说你认为可行的方法,具体怎么做,具体一点说说看,我知道这个问题对于您来说可能是小菜一碟,但对于水平一般的我来说则不同了,所以请各位耐心一点,详细一点,为我指点迷津,也算是为社会主义建设尽了一点力了?谢谢,我代表跟我有着同样疑问的朋友想你们至于崇高的敬意!
问题点数:30、回复次数:18Top
1 楼litsnake1(litsnake)回复于 2002-04-22 12:10:51 得分 0
高手们,开开金口吧!Top
2 楼dylanwolf()回复于 2002-04-22 12:27:53 得分 0
你可以在 DLL中定义一个 getWindowHandle (HWND hReceiveWnd)函数,这样应用程序就可以通过该函数拿到句柄了。Top
3 楼papaya_stone(^_^)shentong(^_^)回复于 2002-04-22 14:54:31 得分 0
为什么要发消息?在DLL中做个导出函数,exe调用该函数时在参数中传递数据不就成了。Top
4 楼cwsuperman(cwsuperman)回复于 2002-04-23 00:05:26 得分 0
简单说一下:
在你的DLL中的函数中加入一个Hwnd变量,然后在主程序中得到函数地址,然后将窗口句柄做为参数发送过去,同时还有消息了,例如:
#####(HWND Hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
Top
5 楼litsnake1(litsnake)回复于 2002-04-23 15:41:20 得分 0
请问是将那个窗口句柄作为参数发送过去?
能不能详细说说,因为这对我来说很重要,谢谢1Top
6 楼voohoo2000(不学无术)回复于 2002-04-23 22:34:35 得分 0
是阿,他们说得很详细了。你说的也对
既然你DLL中想用,那就传给它好了.对不!Top
7 楼litsnake1(litsnake)回复于 2002-04-24 00:42:59 得分 0
不好意思,小弟还是没弄清楚,是不是这个意思:
//在dll中定义一个函数,如:
__declspec (dllexport)test(HWND Hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
.........
}
//当我需要发消息的时候,就在主程序中这样调用
test(hwnd,Mymsg,wpara,lparam);
这样在dll中的test函数中根据uMsg进行处理消息,象窗口函数一样。
请问我这样理解对吗?如果对的话,那我就有几个疑问了:
1。调用test(...)函数时,其中hwnd句柄是不是主程序窗口句柄?
2。test(.....)函数中的Mymsg是不是自定义的消息?
如果我的理解错误的话,那么又是应该怎么样理解的?
谢谢!Top
8 楼yu_hl(卖柴火的小男孩)回复于 2002-04-24 21:00:01 得分 0
1.调用时传入的hwnd是不是主程序窗口自己应该知道吧。这可是自己写的调用程序。
2。什么消息都可以。Top
9 楼cwsuperman(cwsuperman)回复于 2002-04-25 04:20:51 得分 0
To litsnake:
1.Hwnd是一个窗口句柄,可以是任意窗口的,但是必须是接受消息的那个窗口,你明白我的意思吗?因为你要处理消息啊,所以先要接受到消息,再传送给DLL
2.Mymsg和uMsg没有任何的区别,不要忘了,变量名没有任何意义的,仅仅代表参数而已。Top
10 楼litsnake1(litsnake)回复于 2002-04-25 22:42:11 得分 0
To cwsuperman:
你好,您的意思我懂一点,我只是有疑虑而已。
我的这个dll跟主程序并不在同一进程空间中的,而且这个dll是没有窗体的,那么我就不知道接受消息的窗口怎么找,(但是因为这个鼠标钩子dll是强行注入别的进程的,所以不知道把消息发给被注入的进程的窗体,这样不知道消息能不能传给这个dll)。请您帮我解答一下我的疑虑!谢谢!Top
11 楼litsnake1(litsnake)回复于 2002-04-26 11:47:24 得分 0
up
Top
12 楼seeku(青春之歌)回复于 2002-04-26 12:27:56 得分 0
我不知道你想干什么
简直是脱裤子放屁
在程序中调用一下dll中的导出函数不就可以了吗?
所谓发消息
归根到底,不就是调用函数吗?Top
13 楼crazy_lazy_pig(疯狂懒猪)回复于 2002-04-26 12:41:59 得分 0
我也很想知道DLL的知识,请问有没有好的相关的电子书可以下载Top
14 楼cwsuperman(cwsuperman)回复于 2002-04-26 22:19:47 得分 30
To litsnake:
咳,哪天给你一个代码,就清楚了,呵呵。Top
15 楼litsnake1(litsnake)回复于 2002-04-26 22:27:40 得分 0
To cwsuperman:
您好,请问您有代码,如果有这方面的代码,麻烦您给我发一个,在此先谢了!
Email:litsnake@citiz.netTop
16 楼kingzai(stevenzhu)回复于 2002-04-26 22:34:03 得分 0
有好几种方法:
1。再加载一个消息钩子,GetMsgProc,参数可以选择自定义消息或系统的。接到消息后再在同一个DLL里传递数据;
2。可以通过共享内存区,传递数据Top
17 楼litsnake1(litsnake)回复于 2002-04-26 22:48:23 得分 0
其实我很感谢cwsuperman,我觉得高手们应该向cwsuperman学习着点,至少这份耐心是值得我们学习的,不管一个人水平如何高,他总会有疑问的的地方,这就需要大家来共同探讨,懂的就不妨发表一下意见,不懂的学习一下,不要会一点,比别人知道多那么一点就看不起别人。我希望高手们,给多一点耐心,我们问问题就是因为不知道不清楚才会来问的,我想这个论坛目的就是为了解决问题的,在此我再次感谢那些象cwsuperman一样耐心为人解答疑问的高手们,谢谢!Top
18 楼cwsuperman(cwsuperman)回复于 2002-04-28 04:02:49 得分 0
To litsnake:
偶的实验室不能上网,所以没办法把代码拷过来。
我找了一篇文章,你自己看看吧,呵呵。
Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消
息的传递来实现的。而钩子是Windows系统中非常重要的系统接口,用它可以截获
并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子的
种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息
,外壳钩子可以截取、启动和关闭应用程序的消息等。本文在VC5编程环境下实现
了一个简单的鼠标钩子程序,并对Win32全局钩子的运行机制、Win32 DLL的特点
、VC5环境下的MFC DLL以及共享数据等相关知识进行了简单的阐述。
一.Win32全局钩子的运行机制
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当
特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子
函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作
处理而继续传递该消息,还可以强制结束消息的传递。对每种类型的钩子由系统
来维护一个钩子链,最近安装的钩子放在链的开始,而最先安装的钩子放在最后
,也就是后加入的先获得控制权。要实现Win32的系统钩子,必须调用SDK中的AP
I函数SetWindowsHookEx来安装这个钩子函数,这个函数的原型是HHOOK SetWind
owsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);,
其中,第一个参数是钩子的类型;第二个参数是钩子函数的地址;第三个参数是
包含钩子函数的模块句柄;第四个参数指定监视的线程。如果指定确定的线程,
即为线程专用钩子;如果指定为空,即为全局钩子。其中,全局钩子函数必须包
含在DLL(动态链接库)中,而线程专用钩子还可以包含在可执行文件中。得到控
制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须
调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直
接返回TRUE来丢弃该消息,并阻止该消息的传递。
二.Win32 DLL的特点
Win32 DLL与 Win16 DLL有很大的区别,这主要是由操作系统的设计思想决定
的。一方面,在Win16 DLL中程序入口点函数和出口点函数(LibMain和WEP)是分
别实现的;而在Win32 DLL中却由同一函数DLLMain来实现。无论何时,当一个进
程或线程载入和卸载DLL时,都要调用该函数,它的原型是BOOL WINAPI DllMain
(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);,其中,第一个
参数表示DLL的实例句柄;第三个参数系统保留;这里主要介绍一下第二个参数,
它有四个可能的值:DLL_PROCESS_ATTACH(进程载入),DLL_THREAD_ATTACH(线
程载入),DLL_THREAD_DETACH(线程卸载),DLL_PROCESS_DETACH(进程卸载)
,在DLLMain函数中可以对传递进来的这个参数的值进行判别,并根据不同的参数
值对DLL进行必要的初始化或清理工作。举个例子来说,当有一个进程载入一个D
LL时,系统分派给DLL的第二个参数为DLL_PROCESS_ATTACH,这时,你可以根据这
个参数初始化特定的数据。另一方面,在Win16环境下,所有应用程序都在同一地
址空间;而在Win32环境下,所有应用程序都有自己的私有空间,每个进程的空间
都是相互独立的,这减少了应用程序间的相互影响,但同时也增加了编程的难度
。大家知道,在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同
的;而在Win32环境中,情况却发生了变化,当进程在载入DLL时,系统自动把DL
L地址映射到该进程的私有空间,而且也复制该DLL的全局数据的一份拷贝到该进
程空间,也就是说每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同
的。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。
亦即把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的
属性设置为共享。
三.VC5中MFC DLL的分类及特点
在VC5中有三种形式的MFC DLL(在该DLL中可以使用和继承已有的MFC类)可供
选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)和R
egular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MF
C DLL(扩展MFC DLL)。第一种DLL的特点是,在编译时把使用的MFC代码加入到
DLL中,因此,在使用该程序时不需要其他MFC动态链接类库的存在,但占用磁盘
空间比较大;第二种DLL的特点是,在运行时,动态链接到MFC类库,因此减少了
空间的占用,但是在运行时却依赖于MFC动态链接类库;这两种DLL既可以被MFC程
序使用也可以被Win32程序使用。第三种DLL的特点类似于第二种,做为MFC类库的
扩展,只能被MFC程序使用。
四.在VC5中全局共享数据的实现
在主文件中,用#pragma data_seg建立一个新的数据段并定义共享数据,其
具体格式为:
#pragma data_seg ("shareddata")
HWND sharedwnd=NULL;//共享数据
#pragma data_seg()
仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性
,有两种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加
入如下语句:
SETCTIONS
shareddata READ WRITE SHARED
另一种方法是在项目设置链接选项中加入如下语句:
/SECTION:shareddata,rws
五.具体实现步骤
由于全局钩子函数必须包含在动态链接库中,所以本例由两个程序体来实现
。
1.建立钩子Mousehook.DLL
(1)选择MFC AppWizard(DLL)创建项目Mousehook;
(2)选择MFC Extension DLL(共享MFC拷贝)类型;
(3)由于VC5没有现成的钩子类,所以要在项目目录中创建Mousehook.h文件,
在其中建立钩子类:
class AFX_EXT_CLASS Cmousehook:public CObject
public:
Cmousehook();
file://钩子类的构造函数
~Cmousehook();
file://钩子类的析构函数
BOOL starthook(HWND hWnd);
file://安装钩子函数
BOOL stophook();
卸载钩子函数
};
(4)在Mousehook.app文件的顶部加入#include"Mousehook.h"语句;
(5)加入全局共享数据变量:
#pragma data_seg("mydata")
HWND glhPrevTarWnd=NULL;
file://上次鼠标所指的窗口句柄
HWND glhDisplayWnd=NULL;
file://显示目标窗口标题编辑框的句柄
HHOOK glhHook=NULL;
file://安装的鼠标勾子句柄
HINSTANCE glhInstance=NULL;
file://DLL实例句柄
#pragma data_seg()
(6)在DEF文件中定义段属性:
SECTIONS
mydata READ WRITE SHARED
(7)在主文件Mousehook.cpp的DllMain函数中加入保存DLL实例句柄的语句:
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
file://如果使用lpReserved参数则删除下面这行
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
TRACE0("MOUSEHOOK.DLL Initializing!\n");
file://扩展DLL仅初始化一次
if (!AfxInitExtensionModule(MousehookDLL, hInstance))
return 0;
new CDynLinkLibrary(MousehookDLL);
file://把DLL加入动态MFC类库中
glhInstance=hInstance;
file://插入保存DLL实例句柄
}
else if (dwReason == DLL_PROCESS_DETACH)
TRACE0("MOUSEHOOK.DLL Terminating!\n");
file://终止这个链接库前调用它
AfxTermExtensionModule(MousehookDLL);
}
return 1;
}
(8)类Cmousehook的成员函数的具体实现:
Cmousehook::Cmousehook()
file://类构造函数
}
Cmousehook::~Cmousehook()
file://类析构函数
stophook();
}
BOOL Cmousehook::starthook(HWND hWnd)
file://安装钩子并设定接收显示窗口句柄
BOOL bResult=FALSE;
glhHook=SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0);
if(glhHook!=NULL)
bResult=TRUE;
glhDisplayWnd=hWnd;
file://设置显示目标窗口标题编辑框的句柄
return bResult;
}
BOOL Cmousehook::stophook()
file://卸载钩子
BOOL bResult=FALSE;
if(glhHook)
bResult= UnhookWindowsHookEx(glhHook);
if(bResult)
glhPrevTarWnd=NULL;
glhDisplayWnd=NULL;//清变量
glhHook=NULL;
}
}
return bResult;
}
(9)钩子函数的实现:
LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lparam;
if (nCode>=0)
HWND glhTargetWnd=pMouseHook->hwnd;
file://取目标窗口句柄
HWND ParentWnd=glhTargetWnd;
while (ParentWnd !=NULL)
glhTargetWnd=ParentWnd;
ParentWnd=GetParent(glhTargetWnd);
file://取应用程序主窗口句柄
}
if(glhTargetWnd!=glhPrevTarWnd)
char szCaption[100];
GetWindowText(glhTargetWnd,szCaption,100);
file://取目标窗口标题
if(IsWindow(glhDisplayWnd))
SendMessage(glhDisplayWnd,WM_SETTEXT,0,(LPARAM)(LPCTSTR)szCaption);
glhPrevTarWnd=glhTargetWnd;
file://保存目标窗口
}
}
return CallNextHookEx(glhHook,nCode,wparam,lparTop




