2008年(884)
分类: C/C++
2008-08-06 09:50:58
二、程序原理:
首先,我们得能截获鼠标左、右键同时按下去这个事件——这并不难——设一个标志变量当鼠标发出WM_LBUTTONDOWN并且又有WM_RBUTTONDOWN消息发出时把它置“1”罢了。而我要说明的是,这个“同时按下”只是一种宏观上的概念,鼠标是不会同时发出两个消息的。其次就是解决不管鼠标位于任何窗口之上都能在程序里截获(或者称为监听更准确)到鼠标发出的消息并加以过滤的问题了,这是很关键的。我用了钩子船长的那只钩子(Hook),而且是全局的鼠标钩子,它给了我们跟操作系统沟通的一个机会。许多比较有神秘感的程序(比如金山词霸的鼠标取词)都是用它实现的,稍后我将详细解释。最后就是剩下能得到可见的窗口的句柄(HANDLE)并根据其句柄显示、隐藏窗口的问题了,这也没什么难的有现成的API函数——EnumWindows和ShowWindow。你可以先运行一下我的程序(那个大五星,需要把它跟那个Mousehook.dll文件放在一个文件夹下)。当鼠标左右键一起按下时所有的窗口都隐藏了;再一次同时按下左右键又可恢复隐藏窗口;单击任务栏右下角(托盘)的图标可隐藏或显示本程序窗口。
三、开发步骤:
第0步、选用VC 6.0集成开发环境。
第1步、由于建立全局钩子必须把钩子函数放在DLL里面,所以我们选择MFC AppWizard(DLL)创建一个新的项目,命名为“Mousehook”,再选择选择MFC
Extension DLL类型(为了方便嘛!)。为什么必须把全局钩子函数放在DLL里呢?这是因为系统会动态地调用你所添加的全局鼠标钩子,所有窗口消息数都会由于你添加了鼠标钩子而引起系统处理(何为处理?调用钩子函数也。)这必然需要操作系统能够从一个东东里动态地加入这段处理程序,而这个东东非DLL莫属。
第2步、在项目中加入Mousehook.h文件用以构造一个钩子类——CMousehook,具体如下:
class AFX_EXT_CLASS CMousehook:public CObject { public: CMousehook(); ~CMousehook(); BOOL starthook();//封装SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID)用来安装钩子 BOOL stophook(); //封装UnhookWindowsHookEx( HHOOK hhk )用来卸载钩子 VOID SetCheck1(UINT i);//处理对话框的选择钩选框1 VOID SetCheck2(UINT i);//处理对话框的选择钩选框2 VOID SetCheck3(UINT i);//处理对话框的选择钩选框3 static BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam);//系统回调的钩子函数 VOID UseForExit();//退出程序时恢复所有隐藏窗口 };这里我想特别地提一下EnumWindowsProc函数前的CALLBACK跟static,对于CALLBACK我想给大家一个特别江湖的解释其就是:凡是由你设计而却由Windows系统调用的函数,统称callback函数。这些函数都有一定的类型,以配合Windows的调用操作。——引用台湾侯师傅的话。他还说,某些Windows API函数会要求以callback函数(的函数地址)作为其参数之一。我们这里用到的又比如 SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID)的第二个参数。这种API通常会在进行某种行为之后或满足某种状态的情况下调用其参数中的callback函数。又由于系统在调用callback函数的时候并不会借助任何对象去调用该callback函数,所以在用类来封装callback函数时,需要用static来使callback函数能够独立于对象而又属于类的成员函数。明白了不?(啊?地球人都知道呀!太伤自尊了!)
#pragma data_seg("mydata") //编译器识别的指令用以在虚拟内存中开辟一个数据段存放该指令下面的数据 HINSTANCE glhInstance=NULL; //DLL实例(或者说模块)的句柄。 HHOOK glhHook=NULL; //鼠标钩子的句柄。 HWND GlobalWndHandle[100]={NULL,.....};//用来存放被隐藏的窗口的句柄,以数组的形式保存。 //该数组必须初始化,原因见下文。我以“......”省略。 UINT Global_i=0; //用以在循环中序列化窗口数组的变量。 BOOL Condition1=0; //用以记录左键按下或释放的标志变量。 BOOL Condition2=0; //用以记录右键按下或释放的标志变量。 BOOL HideOrVisitableFlag=0; //用以标识当再次有左、右键同时按下的情况发生时是隐藏还是显示窗口。 BOOL Check1=0; //用来表示控件Check1状态的标志变量。 BOOL Check2=0; //用来表示控件Check2状态的标志变量。 BOOL Check3=0; //用来表示控件Check3状态的标志变量。 #pragma data_seg() //与#pragma data_seg("mydata") 首尾呼应表示该数据段的结束。加入上述数据段以后还应在项目里插入一个“Mousehook.def”文件,用:"SECTIONS mydata READ WRITE SHARED"将mydata数据段设置为一个可读写的共享段。在程序里加入预编译指令,或在开发环境的项目设置里也可以达到设置数据段属性的目的,我就不一一赘述了。
临了,希望大家能对我上文中含糊、混沌的地方提出批评指正,也欢迎大家来信(me@sanlian.com.cn)切磋。
下载本文示例代码