写的很随意,这是自己在学习及调试过程的随笔吧,希望能给大家带来一些益处。
很多人对于MFC的入口点及初始化很迷茫,从而导致学习MFC的畏惧心理(当初和我一起学习的3~4个人基本都放弃了),但愿这篇文章给你以启示。
很多人在大学的时候,都被教会程序的入口点是main()函数。但是在main()函数之前有什么操作呢?
这个问题涉及到了程序的加载流程。程序的加载流程大致如下:
加载PE文件的.idata段---->加载PE文件的.data段---->加载代码.text段---->然后执行程序。
.idata是PE文件的引入段。PE文件对外部符号的调用在这里做中转。
.date是PE文件数据段(存放全局的变量)。
.test是PE文件的代码段。
而对于C++程序来说,如果定义了全局的对象,则要调用该对象类的构造函数。
该对象为全局对象,那么该对象将在.data中定义,因此按照加载流程,会在进入入口点之前先调用该对象类的构造函数。
下面来分析下MFC的入口点。
我使用VC6.0新建了一个单文档的工程:MY
在MY.CPP中有一个全局对象CMYApp theApp;
按照上边的分析,会调用该对象的构造函数:
CMYApp::CMYApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}//该处没有任何动作,那么会调用其基类的构造函数CWinApp::CWinApp(LPCTSTR lpszAppName)。
那么我们看看CWinApp::CWinApp(LPCTSTR lpszAppName)的定义吧。
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName);
else
m_pszAppName = NULL;
// initialize CWinThread state
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state
ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
// in non-running state until WinMain
.........
}
只看其中重要的一部分吧。
pModuleState = _AFX_CMDTARGET_GETSTATE();
pModuleState 保存了MFC中的大量重要信息:
1.CWinApp指针
2.实例句柄
3.资源Module的句柄
4.句柄表
5.OLE相关信息
6.窗口过程
7.Activation Context
8.……
那么_AFX_CMDTARGET_GETSTATE()是怎么回事呢?有以下内容可知
#define _AFX_CMDTARGET_GETSTATE() (AfxGetModuleState())
那么AfxGetModuleState()呢?以下是其定义
AFX_MODULE_STATE* AFXAPI AfxGetModuleState()
{
_AFX_THREAD_STATE* pState = _afxThreadState;
AFX_MODULE_STATE* pResult;
if (pState->m_pModuleState != NULL)
{
// thread state's module state serves as override
pResult = pState->m_pModuleState;
}
else
{
// otherwise, use global app state
pResult = _afxBaseModuleState.GetData();
}
ASSERT(pResult != NULL);
return pResult;
}
_afxThreadState 是一个全局的变量,由来如下:
在 AFXSTAT_.H 中 EXTERN_THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)
#define THREAD_LOCAL(class_name, ident_name) /
AFX_DATADEF CThreadLocal<class_name> ident_name; //这里便是 _afxThreadState 被定义的地方。
#define EXTERN_THREAD_LOCAL(class_name, ident_name) /
extern AFX_DATA THREAD_LOCAL(class_name, ident_name)
在AFXTLS_.H中定义
template<class TYPE>
class CThreadLocal : public CThreadLocalObject
{}
为了加深你的理解,你可以继续往下追 CThreadLocal 和 CThreadLocalObject 的定义,也比较的简单了,就是new了一个对象。
到了这里就要思考一个问题了:那么我们自己定义的对象和程序的入口点有什么关系呢?
哈哈,往上看看CWinApp::CWinApp(LPCTSTR lpszAppName)的定义,其中有两条如下的语句:
pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this;
这两条语句就是我们应用程序和MFC的入口点 AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) 的关键所在了。
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
...........
CWinThread* pThread = AfxGetThread();//线程对象 THRDCORE.CPP:CWinThread* AFXAPI AfxGetThread()
CWinApp* pApp = AfxGetApp();// 主对象 AFXWIN1.INL:_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
...........
}
看到这里应该明白了吧。
在CWinApp::CWinApp(LPCTSTR lpszAppName)中对全局的变量_afxThreadState进行了初始化,然后到了入口点后,就能够通过AfxGetApp()获取到theApp,并使用它了。
pApp->InitApplication();就能够调用我们所建工程MY的BOOL CMYApp::InitInstance()函数了。因为CWinApp::InitInstance()是虚函数。
本人也是刚参加工作,在各方面还有很多欠缺,希望没有给你带来误导就好。
本文探讨了MFC程序的入口点和初始化过程,详细分析了从PE文件加载到CWinApp构造函数的执行,解释了_AFX_CMDTARGET_GETSTATE()、CWinThread和CWinApp之间的关系,以及如何通过AfxGetApp()获取应用实例并调用InitInstance()函数。
935

被折叠的 条评论
为什么被折叠?



