在做一个模块测试,将MFC程序中的主窗口句柄、成员变量、全局变量作为参数传入DLL并将值保存到DLL的全局变量中,发现在钩子函数HOOK的回调函数中调用到的DLL全局变量都是空值(吓尿了),也就是说从外部传入的值虽然保存在DLL的全局变量里,但是钩子函数的回调函数根本获取不到!!!可是需要这些变量跟MFC程序进行消息交互呀!!怎么会这样?为什么会这样?
其实每次触发钩子回调函数的都是不同的线程,每个线程系统都分配了不同的地址空间,仅仅是名字相同【恍然大悟呀】。
被多个线程共用,要想使用该全局变量,那么该全局变量必须是共享的!!所以要把这些全局变量放到一个叫做DLL共享数据段的东东内。
但是注意,共享数据段的设置需要符合一定的前提条件,否则白搭。
以下是核心代码:
#include "stdafx.h"
#include <Dbt.h>
#include "DeviceChangeDetect.h"
#define WM_MY_TEST (WM_USER+100)
/*
数据段内变量需要主要以下几点,否则数据段设置不生效:
a、共享段的大小空间必须确定,不要使用string、CString等这种大小不明确的【用数组代替】
b、定义了一个变量,必须初始化,不管是什么类型都要初始化
c、要写完整,一共【①设置权限】【②指定数据段的名字及权限】【③数据段结束】
*/
//①设置数据段为可读可写可共享
#pragma comment(linker,"/section:.ShareSeg,rws")
//②设置共享数据段,目的是让模块中[包括回调函数]都能操作全局变量,每个变量都必须初始化
#pragma data_seg(".ShareSeg")
HHOOK glhHook=NULL; //钩子句柄。
HINSTANCE glhInstance=NULL; //DLL实例句柄。
HWND gHwnd = NULL;
WCHAR wcWndName[256]={0};
//③共享数据段结束
#pragma data_seg()
extern "C" LRESULT WINAPI DeviceChangeProc(int nCode,WPARAM wParam,LPARAM lParam)
{
int nW = 1;
int nL = 2;
switch(nCode)
{
case HC_ACTION:
PCWPSTRUCT pMsg = PCWPSTRUCT(lParam);
if ( pMsg->message == WM_DEVICECHANGE )
{
switch( pMsg->wParam )
{
case DBT_DEVICEARRIVAL:
//gHwnd = FindWindow(NULL,_T("DLLCatchDevChange"));//使用该方法可以找到指定的窗口句柄
::SendMessage(gHwnd,WM_MY_TEST,nW,nL);//与传入的句柄窗口进行消息交互
break;
case DBT_DEVICEQUERYREMOVE:
// Handle device removal request
AfxMessageBox(_T("COM Change"));
break;
case DBT_DEVICEREMOVECOMPLETE:
// Handle device removal
AfxMessageBox(_T("COM Has removed"));
break;
}
}
}
return CallNextHookEx(glhHook,nCode,wParam,lParam);
}
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
glhInstance = (HINSTANCE)hInstance;//非常重要,此时要先获得这个模块的句柄
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
//AfxMessageBox(L"Entry");
return TRUE;
}
//安装全局钩子。
HHOOK CDeviceChangeHook::Start(HWND hWnd)
{
gHwnd = hWnd;
if (NULL == gHwnd)
{
AfxMessageBox(_T("hWnd is NULL"));
return NULL;
}
glhHook = SetWindowsHookEx(WH_CALLWNDPROC/*WH_GETMESSAGE*/,DeviceChangeProc,glhInstance,0);//根据模块句柄glhInstance设置钩子函数
return glhHook;
}
//卸载全局钩子。
BOOL CDeviceChangeHook::Stop()
{
BOOL bResult = TRUE;
if( glhHook )
bResult = UnhookWindowsHookEx(glhHook);//卸载钩子。
return bResult;
}