打怪升级之MFC的WinMain函数

按惯例,这一篇文章主要还是作者读《深入浅出MFC》整理的一些笔记。

WinMain函数在哪里?

CWinApp和CFrameWnd类:前者代表了程序而本体,后者代表了一个框架窗口。

CwinApp取代了WinMain的地位,而CFrameWnd取代了WndProc的地位。

virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();

在“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\include\afxwin.h”文件夹下,可以找到CWinApp的类名。在CWinApp类中,主要起作用的就是上述三类函数。

由CWinApp类定义一个theApp变量后,定义在CWinApp类中的各变量都会有一个实际的例程。在“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc、winmain.cpp”中是MFC实际的winmain程序,之所以在theApp配置中没有明显的winmain函数,是因为MFC单独在此准备了main函数并由链接器直接加到应用程序代码中。

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	_In_ LPTSTR lpCmdLine, int nCmdShow)
{
	ASSERT(hPrevInstance == NULL);//判断上一同句柄进程是否存在。

	int nReturnCode = -1;
	CWinThread* pThread = AfxGetThread();//获取由进程函数创造的线程
	CWinApp* pApp = AfxGetApp();//这是一个全局函数,定义在AFXWIN1.INL中,又进一步定义在AFXWIN.H中

	// AFX internal initialization
	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))//AFX初始化
		goto InitFailure;

	// App global initializations (rare)
	if (pApp != NULL && !pApp->InitApplication())//APP初始化
		goto InitFailure;

	// Perform specific initializations
	if (!pThread->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();//开始进程

InitFailure://失败后打印错误
#ifdef _DEBUG
	// Check for missing AfxLockTempMap calls
	if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
	{
		TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
			AfxGetModuleThreadState()->m_nTempMapLock);
	}
	AfxLockTempMaps();
	AfxUnlockTempMaps(-1);
#endif

	AfxWinTerm();
	return nReturnCode;
}

应该反过来说,是winmain函数调用了theWinApp类,而不要期望在winapp中找到winmain函数。主函数在判断完没有多开程序进程之后,开始分别进入AFX初始化、APP初始化、线程初始化、执行、关闭流程。

为了加深理解,这里笔者强调,所谓MFC是一个封装完备的类库,就是因为把这些原本你可以操作的东西都隐藏起来了,只让你作用App类,只让你关心各具体组件,不想你关心报错、初始化、WindowsAPI函数调用等其他的问题。

如果你有特殊的程序需求,必须要拆开MFC不可的时候,就沿着这一文件的路径去做吧,这里的winmain函数与winapp类高度绑定。winmain通过各类获取函数间接的控制间接的控制着app类。

AfxWinInit内部初始化

Afx动作记录在APPINIT.CPP中,具体路径参考为:“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc\appinit.cpp”中(src内文件的风格就是,一个文件做一个函数)。这个函数的主要作用是初始化MFC,如果你调用此函数,应该首先定义一个CWinApp类的实例。

BOOL AFXAPI AfxWinInit(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
	_In_z_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
	ASSERT(hPrevInstance == NULL);//判断有无先前程序存在

	// handle critical errors and avoid Windows message boxes
	SetErrorMode(SetErrorMode(0) |
		SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);//报错格式设置

	// set resource handles
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();//获取当前初始化状态
	pModuleState->m_hCurrentInstanceHandle = hInstance;//将状态栏内变量指向实际程序句柄
	pModuleState->m_hCurrentResourceHandle = hInstance;

	// fill in the initial state for the application
	CWinApp* pApp = AfxGetApp();//获取当前App类
	if (pApp != NULL)
	{
		// Windows specific initialization (not done if no CWinApp)
		pApp->m_hInstance = hInstance;//将各个值赋给当前App类
		hPrevInstance; // Obsolete.
		pApp->m_lpCmdLine = lpCmdLine;
		pApp->m_nCmdShow = nCmdShow;
		pApp->SetCurrentHandles();
	}

	// initialize thread specific data (for main thread)
	if (!afxContextIsDLL)
		AfxInitThread();//开始线程进程初始化

	return TRUE;
}

不过这个AFX的函数在初始化了APP之后还没写完,还要继续初始化线程(thread),所以要去“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc\thrdcore.cpp”找AfxInitThread函数:

void AFXAPI AfxInitThread()
{
	if (!afxContextIsDLL)
	{
		// set message filter proc
		_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
		ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
		pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFILTER,
			_AfxMsgFilterHook, NULL, ::GetCurrentThreadId());
	}
}

到此,MFC的初始化工作做完,主要任务是:1.获取当前APP,并将来自系统的程序句柄、程序参数输入给app;2.初始化线程,并将由系统函数开辟的进程或线程赋值告知MFC。

CWinApp类的初始化、实例化

CWinApp类内函数的定义,去往"…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc\appcore.cpp"文件内去找。其中winmain函数里出现的app初始化函数定义如下:

BOOL CWinApp::InitApplication()
{
	if (CDocManager::pStaticDocManager != NULL)
	{
		if (m_pDocManager == NULL)
			m_pDocManager = CDocManager::pStaticDocManager;
		CDocManager::pStaticDocManager = NULL;
	}

	if (m_pDocManager != NULL)
		m_pDocManager->AddDocTemplate(NULL);
	else
		CDocManager::bStaticInit = FALSE;

	LoadSysPolicies();

	return TRUE;
}

显而易见,主要目的,也就是做一些参数赋值,或者是为参数建立内存变量。在完成变量初始化后,开始进行变量实例化:

BOOL CWinApp::InitInstance()
{
	InitLibId();
	m_hLangResourceDLL = LoadAppLangResourceDLL();
	if(m_hLangResourceDLL != NULL)
	{
		AfxSetResourceHandle(m_hLangResourceDLL);
		_AtlBaseModule.SetResourceInstance(m_hLangResourceDLL);
	}

	// Register the application with the Restart Manager, if supported.
	if (SupportsRestartManager())
	{
		RegisterWithRestartManager(SupportsApplicationRecovery(), _T(""));
	}

	// If the application is linked statically to MFC, then cleanup of the globals
	// does not need to be reference counted.  Otherwise, we need to make sure that
	// the last CWinApp to exit does the cleanup of all the globals.

#ifdef _AFXDLL
	AfxGlobalsAddRef();
#endif

	return TRUE;
}

应用程序一定要改写虚函数,因为它在CWinApp内只是各空函数,没有内建动作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

考琪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值