我只是想解释一下为什么需要使用一个共享的数据段,如下:
#pragma data_seg("mydata") //编译器识别的指令用以在虚拟内存中开辟一个数据段存放该指令下面的数据
HINSTANCE glhInstance=NULL; //DLL实例(或者说模块)的句柄。
HHOOK glhHook=NULL; //鼠标钩子的句柄。
HWND GlobalWndHandle[100]={NULL,.....};//用来存放被隐藏的窗口的句柄,以数组的形式保存。
//该数组必须初始化,原因见下文。我以“......”省略。
#pragma data_seg() //与#pragma data_seg("mydata") 首尾呼应表示该数据段的结束。
加入上述数据段以后还应在项目里插入一个“*def”文件,用:"SECTIONS mydata READ WRITE SHARED"将mydata数据段设置为一个可读写的共享段。在程序里加入预编译指令,或在开发环境的项目设置里也可以达到设置数据段属性的目的,我就不一一赘述了。
我前面讲过,系统通过调用放在DLL中的钩子回调函数来实现全局钩(钩取所有窗口的鼠标消息),操作系统对DLL的操作仅仅是把DLL映射到需要它的进程的虚拟地址空间里去。也就是说,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。“DLL在WIN32中什么都不拥有”——这句话很重要。比如我们在DLL里建立了一个变量a,而我们的这个DLL文件又被两个进程所调用,这两个进程的中都用到了a可这绝对是两个不同存储单元中存储的两个a,它们之间没有丝毫的联系。给其中一个赋值也绝对不会影响到另一个。而对于本程序的一些数据是需要在不同的进程中保持唯一的(也可以说是一致),比方说: HWND GlobalWndHandle[100]它是用来保存程序做了隐藏的窗口之句柄的数组。当程序运行,我在任意窗口A中同时按下了鼠标左、右键,由于设置了鼠标钩子,系统会调用DLL中的钩子处理函数截获消息并加以处理,即把目前的可见窗口隐藏并把窗口句柄保存到GlobalWndHandle[100]数组中以备将来显示之用。如果不把GlobalWndHandle[100]放到一个共享的数据段里,系统就会在目前我们截获鼠标消息的A窗口的进程的地址空间里开辟HWND GlobalWndHandle[100]来存储窗口句柄。这样对于其他进程就不能方便地得到这个进程存入GlobalWndHandle[100]数组的数据了。这时只能将GlobalWndHandle[100]等需要跨进程访问的变量数据放在一个共享的数据段里了。另外,需要特别注意——必须给这些变量赋初值(就象我在程序代码里傻呼呼地写了100个NULL一样。你可以不初始化这个数组试验一下,有助于你理解我上面的话),否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。
简单的说(在制作老板键的时候)由于dll什么都没有,dll中的全局变量实际上是在窗口中,所以在隐藏窗口后,你原先存储在dll中的hwnd随窗口而隐藏,你无法选中窗口,也无法取得此Hwnd。所以无法恢复窗口,解决办法就是开一段共享空间。从而可以在任何时候获取到Hwnd。