MFC实例分析

本文详细解析了MFC框架的启动流程,从_tWinMain函数的调用开始,介绍了AfxWinMain函数的作用,以及CHelloWordApp::InitInstance()中的窗口创建过程。深入探讨了AfxGetThread()与AfxGetApp()的区别,窗口钩子AfxCbtFilterHook的安装和AfxWndProc()的窗口消息处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实例HelloWord.cpp 首先创建一个CHelloWordApp theApp类型的全局变量;调用完CHelloWordApp 和CWinAppEx以及CWinApp的构造函数以后进入
extern “C” int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
In LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
在TCHAR.h中,有此定义:#define _tWinMain WinMain,所以这里的_tWinMain就是WinMain函数。它调用了AfxWinMain函数(位于WinMain.cpp中)。
在_tWinMain调用了AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow),
在AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
{
// App global initializations (rare)
CWinThread* pThread = AfxGetThread();//得到当前应用程序指针
CWinApp* pApp = AfxGetApp();//AfxGetApp()返回的是应用程序对象theApp的指针.

if (pApp != NULL && !pApp->InitApplication())
	goto InitFailure;
if (!pThread->InitInstance())//访问到HelloWord程序中的InitInstance了;
{
	if (pThread->m_pMainWnd != NULL)
	{
		TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
		pThread->m_pMainWnd->DestroyWindow();
	}
	nReturnCode = pThread->ExitInstance();
	goto InitFailure;
}
nReturnCode = pThread->Run();//进入消息循环;

}

MFC里AfxGetThread()与AfxGetAPP()的区别
复制代码
1 CWinThread* AFXAPI AfxGetThread()
2 {
3 // check for current thread in module thread state
4 AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
5 CWinThread* pThread = pState->m_pCurrentWinThread;
6
7 // if no CWinThread for the module, then use the global app
8 if (pThread == NULL)
9 pThread = AfxGetApp();
10
11 return pThread;
12 }
复制代码
复制代码
1 _AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
2 {
3 return afxCurrentWinapp;
4 }
5 //在AFXWIN.H中 #define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
6 //AfxGetModuleState()就是得到当前模块,AfxGetModuleState()->m_pCurrentWinApp=this;得到当前应用程序的对象指针
复制代码
AfxGetThread()返回的是当前界面线程对象的指针,AfxGetApp()返回的是应用程序对象theApp的指针.

如果该应用程序(或进程)只有一个界面线程在运行,那么这两者返回的都是一个全局的应用程序对象theApp的指针。

如果在多线程时调用AfxGetThread返回的与AfxGetApp并不一定相同。

nReturnCode = pThread->Run();//进入消息循环;
进入函数后发现:
int CWinApp::Run()
{
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
{
// Not launched /Embedding or /Automation, but has no main window!
TRACE(traceAppMsg, 0, “Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n”);
AfxPostQuitMessage(0);
}
return CWinThread::Run();//进入这个Run()

}
CHelloWordApp::InitInstance()里面会创建一个
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) 窗口
创建窗口的同时会安装AfxCbtFilterHook
// 安插AfxCbtFilterHook
AfxHookWindowCreate(this);

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

	if (pThreadState->m_hHookOldCbtFilter == NULL)
	{
		// 安插_AfxCbtFilterHook,因为_AfxCbtFilterHook()是一个基于计算机训练的hook,  
        // 所以windows在激活、创建、销毁、最大化、最小化、移动窗口或改变窗口大小之前,  
        // 会调用_AfxCbtFilterHook() 
		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;
}
_AfxCbtFilterHook通过SetWindowLongPtr函数将窗口的处理函数替换成AfxWndProc(),同时,在CWnd::m_pfnSuper中保存原来的窗口消息处理函数指针;下面截取一小段:
LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData()
	if (code != HCBT_CREATEWND)
	{
		// wait for HCBT_CREATEWND just pass others on...//在调用create Wind 的时候会触发这个消息;
		return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
			wParam, lParam);
	}
	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);
			// 将窗口的消息处理函数设置成AfxWndProc()
			// 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;
		}
下面是AfxWndProc函数定义
LRESULT CALLBACK
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	// special message which identifies the window as using AfxWndProc
	if (nMsg == WM_QUERYAFXWNDPROC)
		return 1;

	// all other messages route through message map
	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
	ASSERT(pWnd != NULL);					
	ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd);
	if (pWnd == NULL || pWnd->m_hWnd != hWnd)
		return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
	return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}

Run中会调用LRESULT CALLBACK
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// special message which identifies the window as using AfxWndProc
if (nMsg == WM_QUERYAFXWNDPROC)
return 1;

// all other messages route through message map
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
ASSERT(pWnd != NULL);					
ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd);
if (pWnd == NULL || pWnd->m_hWnd != hWnd)
	return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值