问题是这样,我做了个钩子程序调用Setwindowlongptr来子类化一个窗口上listview控件,钩子没有任务问题,setwindowlongptr也能调用有返回,但被我hook的那个窗口却出了问题,老是弹出0xXXXXX内存不能read,然后就崩掉了。调试许久找不出原因,后来我尝试了一下用我的dll去子类化别的窗口,结果却正确了,我用spy++,查看了一下两个窗口,发现失败的那个窗口,原先是已经被子类化了的。而成功被我子类化的那个窗口则没有,除此两者没有太大差别。不知是不是因为已经子类化过的窗口就不能再被子类了?因为我的程序去子类化别的窗口的时候可都是成功的。就子类化listview的时候有问题。源码我回去后再贴出来给大家看看,希望可以得到高价指示!
即使是MFC对象中使用的SubclassWindow 最后调用的也是SetWindowLong
CallWindowProc
进行默认处理。。
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
SendMessage(HwndOfSeverForm,WM_USER+87,Msg,lParam); //return DefWindowProc(hWnd,Msg,wParam,lParam);
return CallWindowProc(OldWndProc,hWnd, Msg, wParam, lParam);
}
LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { static BOOL bFirstTime = TRUE; if (bFirstTime) {
// The DLL just got injected.
bFirstTime = FALSE;
// LRESULT (CALLBACK* )(HWND, UINT, WPARAM, LPARAM)OldWndProc=(LRESULT (CALLBACK* )(HWND, UINT, WPARAM, LPARAM))GetWindowLong(g_HandleOfAlarmLV,GWL_WNDPROC);
OldWndProc=(WNDPROC)SetWindowLongPtr(g_HandleOfAlarmLV,GWLP_WNDPROC,(LONG_PTR)MyWndProc);
if(OldWndProc!=NULL)
MessageBox(NULL, TEXT("DLL已成功改变预警系统窗口消息。"), TEXT("信息"), MB_ICONINFORMATION );
// Uncomment the line below to invoke the debugger
// on the process that just got the injected DLL.
// ForceDebugBreak(); // Create the DIPS Server window to handle the client request. // Tell the DIPS application that the server is up
// and ready to handle requests.
} return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
BOOL WINAPI SetMyHook(DWORD ThreadId,HWND handleOfAlarmLV,HWND handleOfSever)
{
BOOL OK=FALSE;
if(ThreadId!=0)
{
//chASSERT(g_hHook==NULL);
if(g_hHook!=NULL)
return false; HwndOfSeverForm=handleOfSever;
g_HandleOfAlarmLV=handleOfAlarmLV;
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,g_HandleOfDll,ThreadId);
OK=(g_hHook!=NULL);
if(OK)
{
OK=PostThreadMessage(ThreadId,WM_NULL,0,0);
}
}
else
{
if(g_hHook==NULL)return false;
OK=UnhookWindowsHookEx(g_hHook);
g_hHook=NULL;
}
return OK;
}我在测试该dll的时候用的时候win32控制台项目,用两个EnumChildWindows(NULL,EnumChildProc,NULL)来查找目标窗口的句柄,因为窗口标题是变化的,而类名又是#32770 (对话框),这个样子根本没法用findwindow来找,只能enumchildwindows来一个个搜,但enumchildwindows中再用enumchildwindows,最后才sethook这个样子,还没等开始hook主线程就已经结束了,我当时只好createthread来另开线程,并用waitforsingleobject来等待,这个样子之后就能sethook了,逐步调试来做就很成功,能够子类化目标窗口,但若不设断点直接运行就会出问题,我反复调试觉得好像是线程返回的时候有些东西没处理好,可惜到现在也没发现是什么问题。只知道如若直接把目标窗口的句柄(及线程ID)传给我的钩子函数,一切就能正常。很奇怪!如下为测试项目代码:
BOOL CALLBACK EnumChildProc2(HWND hwnd, LPARAM lParam )
{
if (!hwnd)
{
return 0;
} WCHAR str[14];
GetClassName(hwnd,str,14); WCHAR str2[14]=TEXT("SysListView32"); int i; for(i=0;i<14;i++)
{
if(str[i]!=str2[i])
break;
} if(i!=14)
return true;
WCHAR str3[6]=TEXT("List2");
GetWindowText(hwnd,str,6); for(i=0;i<5;i++)
{
if(str[i]!=str3[i])
break;
} if(i!=5)
return true; HwndOfLV=hwnd;
HINSTANCE Hinst=LoadLibrary(TEXT("HookMsg.dll"));
SetHook=(BOOL (WINAPI * )(DWORD ,HWND,HWND ))GetProcAddress(Hinst,"SetMyHook");
BOOL k=SetHook(GetWindowThreadProcessId(hwnd,NULL),hwnd,HwndOfSeverForm);
return false;
}BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam )
{ if (!hwnd)
{
return false;
} WCHAR str[6];;
GetWindowText(hwnd,str, 6); int i;
WCHAR str2[3]=TEXT("预警");
for(i=0;i<2;i++)
{
if(str2[i]!=str[i])
break;
}
if(i==2)
{
EnumChildWindows(hwnd,EnumChildProc2,NULL);
return false;
}
return true;
}
DWORD WINAPI GetWinHwnd (PVOID pvParam)
{
HwndOfSeverForm=FindWindow(TEXT("WindowsForms10.Window.8.app.0.378734a"),TEXT("服务器主端")); if(HwndOfSeverForm==NULL)
{
MessageBox(NULL,TEXT("找不到SEVER!"),TEXT("注意"),MB_ICONINFORMATION);
return 0;
}
EnumChildWindows(NULL,EnumChildProc,NULL); return 0; }
int _tmain(int argc, _TCHAR* argv[])
{
//HwndOfSeverForm=FindWindow(TEXT("WindowsForms10.Window.8.app.0.378734a"),TEXT("服务器主端"));
HANDLE Handle=CreateThread(NULL,0,GetWinHwnd,NULL,0,NULL);
WaitForSingleObject(Handle,INFINITE);
//if(HwndOfLV==NULL)
// {
//MessageBox(NULL,TEXT("找不到预警窗口!"),TEXT("注意"),MB_ICONINFORMATION);
// return 0;
//}
//BOOL ok=InjectLib(GetWindowThreadProcessId(hwnd,NULL),TEXT("HookMsg.dll"));
/////////////////
//
/// 注意线程的操作即可,dll已无问题!!!!!!!!!!
///
///////////////////////// while(1)
{}
return 0;}