CWnd截获WM_CREATE消息剖析

    使用MFC开发应用程序时,发现CWnd(及其继承类)可以处理WM_CREATE消息。根据之前对MFC消息的理解,所有的MFC窗口类共享一个窗口函数,在窗口函数中利用全局句柄映射表得到CWnd指针,然后调用虚函数WndProc。问题来了,窗口创建完成后,得到窗口句柄,这时候CWnd对象与窗口句柄再做关联,此时WM_CREATE消息已经处理完毕了,CWnd对象应该捕获不了WM_CREATE消息啊!MFC应该采用了另外的方式处理CWnd与窗口句柄的映射关系,于是跟踪源代码,得到了答案。

   在CWnd::CreateEx方法中,在创建窗口之前,安装了窗口创建消息钩子(WH_CBT)。并且在线程状态中存储了CWnd指针,以下为源代码

void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
	if (pThreadState->m_pWndInit == pWnd)
		return;

	if (pThreadState->m_hHookOldCbtFilter == NULL)
	{
		pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
			_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
		if (pThreadState->m_hHookOldCbtFilter == NULL)
			AfxThrowMemoryException();
	}
	ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);
	ASSERT(pWnd != NULL);
	ASSERT(pWnd->m_hWnd == NULL);   // only do once

	ASSERT(pThreadState->m_pWndInit == NULL);   // hook not already in progress
	pThreadState->m_pWndInit = pWnd;
}


窗口创建时,消息钩子函数首先获得处理,其将CWnd与句柄映射

LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
	..............

	CWnd* pWndInit = pThreadState->m_pWndInit;
	BOOL bContextIsDLL = afxContextIsDLL;
	if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !bContextIsDLL))
	{
		

		ASSERT(wParam != NULL); // should be non-NULL HWND
		HWND hWnd = (HWND)wParam;
		WNDPROC oldWndProc;
		if (pWndInit != NULL)
		{
			AFX_MANAGE_STATE(pWndInit->m_pModuleState);

			// the window should not be in the permanent map at this time
			ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL);

			// connect the HWND to pWndInit...
			pWndInit->Attach(hWnd);
			// allow other subclassing to occur first
			pWndInit->PreSubclassWindow();

			WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
			ASSERT(pOldWndProc != NULL);

			// subclass the window with standard AfxWndProc
			WNDPROC afxWndProc = AfxGetAfxWndProc();
			oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,
				(DWORD_PTR)afxWndProc);
			ASSERT(oldWndProc != NULL);
			if (oldWndProc != afxWndProc)
				*pOldWndProc = oldWndProc;

			pThreadState->m_pWndInit = NULL;
		}
		else
		{
			......
		}
}


当窗体接收WM_CREATE函数时,就能找到对应的CWnd对象,而后调用OnCreate函数。

在创建完窗口后,调用AfxUnhookWindowCreate注销消息钩子函数,以下为CWnd::CreateEx源代码

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName, DWORD dwStyle,
	int x, int y, int nWidth, int nHeight,
	HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
	ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) || 
		AfxIsValidAtom(lpszClassName));
	ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
	
	// allow modification of several common create parameters
	CREATESTRUCT cs;
	cs.dwExStyle = dwExStyle;
	cs.lpszClass = lpszClassName;
	cs.lpszName = lpszWindowName;
	cs.style = dwStyle;
	cs.x = x;
	cs.y = y;
	cs.cx = nWidth;
	cs.cy = nHeight;
	cs.hwndParent = hWndParent;
	cs.hMenu = nIDorHMenu;
	cs.hInstance = AfxGetInstanceHandle();
	cs.lpCreateParams = lpParam;

	if (!PreCreateWindow(cs))
	{
		PostNcDestroy();
		return FALSE;
	}

	AfxHookWindowCreate(this);
	HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
			cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
			cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

#ifdef _DEBUG
	if (hWnd == NULL)
	{
		TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
			GetLastError());
	}
#endif

	if (!AfxUnhookWindowCreate())
		PostNcDestroy();        // cleanup if CreateWindowEx fails too soon

	if (hWnd == NULL)
		return FALSE;
	ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
	return TRUE;
}


 

 

 

展开阅读全文

全局HOOK截获WM_CREATE消息为什么不行??

11-06

mydll.cpp部分代码贴出如下rn[code=C/C++]rnLRESULT CALLBACK HookProc(int code,WPARAM wparam,LPARAM lparam)rnrn if(code<0) rn return ( CallNextHookEx(g_hHook, code, wparam, lparam)); rn rn CWPSTRUCT *pcw = reinterpret_cast(lparam);rn if(LOWORD(pcw->message) == WM_CREATE)rn rn ::PostMessage(g_hWndCaller, [color=#FF0000]HM_GETMSG[/color], wparam, lparam); //发送自定义消息 rn rn return ::CallNextHookEx(g_hHook,code,wparam,lparam); rnrnrnBOOL WINAPI SetMsgHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller) rnrn BOOL bOk;rn g_hWndCaller = hWndCaller;rn if(bInstall) rn rn g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE,HookProc,rn GetModuleHandle("myDll"),dwThreadId);//[b]dwThreadId=0[/b]rn bOk = (g_hHook != NULL); rn rn elsern rn bOk = ::UnhookWindowsHookEx(g_hHook);rn g_hHook = NULL;rn rn return bOk;rnrn[/code]rnMsgDlg.cpp部分代码如下:rn[code=C/C++]rn对话框类的WM_CREATE相应函数中调用SetMsgHook()rnint CMsgDlgDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) rnrn if (CDialog::OnCreate(lpCreateStruct) == -1)rn return -1;rn rn // TODO: Add your specialized creation code herern if(!SetMsgHook(TRUE,0,m_hWnd))rn MessageBox("安装钩子失败");rn return 0;rnrnrn在自定义消息HM_GETMSG的消息响应函数中rnLRESULT CMsgDlgDlg::onMsgKey(WPARAM wParam, LPARAM lParam) rnrn MessageBox("截获到了创建消息");rnrn[/code]rn我运行MsgDlg程序时,感觉MsgDlg程序象死掉一样,调试DLL发现钩子创建成功,也能执行到::PostMessage这一步,rn按理说程序应该能截获到MsgDlg程序的消息,可是为什么会程序运行象死掉的一样啊,我想是不是::PostMessage的rn原因?(换成WH_CALLWNDPROC也是一样)rn请大家给我指点指点 论坛

没有更多推荐了,返回首页