MFC应用程序不但具有一般的Win32程序的主要入口WinMain函数,还有一个CWinApp派生类的全局实例 theApp。
Mfc程序(EXE)的程序运行过程如下:
首先是全局构造
CObject构造函数à CCmdTarget àCWinThreadàCWinAppà theApp构造函数
然后进入WinMain函数
WinMainàAfxWinMainàAfxWinInitàtheApp.InitApplicationàtheApp.InitInstance
接着执行线程过程。
theApp.Run()
最后清理
AfxWinTerm
在各种初始化函数中,反复调用了AfxGetApp和AfxGetThread函数。在WinMain过程中,这两个函数实际上返回同一实例指针theApp。在其它线程中,AfxGetThread返回当前线程对象,这也就是为什么在MFC中新建线程不能使用CreateThread和beginthread(ex),而要使用AfxBeginThread。后者会创建一个CWinThread的实例。
AfxGetApp和AfxGetThread这两个全局函数是如何得知当前应用程序对象(theApp)和当前线程对象呢?在MFC中,有一个AFX_MODULE_STATE全局实例_afxBaseModuleState
(实际代码中_afxBaseModuleState是_AFX_BASE_MODULE_STATE的实例,而_AFX_BASE_MODULE_STAT只是前者的一个包装,直接继承AFX_MODULE_STATE类,为了简化关系,这里把它们等同起来)。它以下划线开始,所以被认为是内部使用,不能直接操作。直接操作它的是函数AfxGetAppModuleState。
AFX_MODULE_STATE的定义相当复杂,很多是为其它部件保留的与模块(EXE)相关状态参数(所以命名为MODULE_STATE)。下面只列出与初始化过程相关的部分:
1|. class AFX_MODULE_STATE : public CNoTrackObject
2|. {
3|. public:
4|. #ifdef _AFXDLL
5|. AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
6|. BOOL bSystem = FALSE);
7|. #else<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
8|. explicit AFX_MODULE_STATE(BOOL bDLL);
9|. #endif
10|. ~AFX_MODULE_STATE();
11|.
12|. CWinApp* m_pCurrentWinApp;
13|. HINSTANCE m_hCurrentInstanceHandle;
14|. HINSTANCE m_hCurrentResourceHandle;
15|. LPCTSTR m_lpszCurrentAppName;
16|. BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXE
17|. BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
18|. BYTE m_bReserved[2]; // padding
19|. // define thread local portions of module state
20|. CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;
21|. };
函数AfxGetApp返回的正是_afxBaseModuleStat中m_pCurrentWinApp 成员。
_AFXDLL部分与MFC Regular Dll相关,暂不讨论。而AFX_MODULE_STATE秉承MFC的一贯原则,构造函数只保证了数据结构的有效性,而未对数据内容做出任何保证。因此,_ afxBaseModuleState构造后,其内容还是未知的。仅从成员可以知道,该类表示CWinApp所在模块(EXE)。而它的成员m_thread则表达了该模块中线程的状态(其实际类型为AFX_MODULE_THREAD_STATE)。该类的相关定义如下:
22|. class AFX_MODULE_THREAD_STATE : public CNoTrackObject
23|. {
24|. public:
25|. AFX_MODULE_THREAD_STATE();
26|. virtual ~AFX_MODULE_THREAD_STATE();
27|.
28|. // current CWinThread pointer
29|. CWinThread* m_pCurrentWinThread;
30|.
31|. };
AfxGetThread函数正是由_afxBaseModuleState取得取了AFX_MODULE_THREAD_STATE中的m_pCurrentThread成员。
下面是CCmdTarget,CWinThread和CWinApp构造函数中对以上成员变量初始化的过程。
CCmdTarget
无
CWinThread
32|. CWinThread::CWinThread()
33|. {
34|. …
35|. CommonConstruct();
36|. }
37|.
38|. void CWinThread::CommonConstruct()
39|. {
40|. …
41|. _AFX_THREAD_STATE* pState = AfxGetThreadState();
42|. // initialize message pump
43|. #ifdef _DEBUG
44|. pState->m_nDisablePumpCount = 0;
45|. #endif
46|. pState->m_msgCur.message = WM_NULL;
47|. pState->m_nMsgLast = WM_NULL;
48|. …
49|. }
CWinApp
50|. CWinApp::CWinApp(LPCTSTR lpszAppName)
51|. {
52|. …
53|. // initialize CWinThread state
54|. AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
55|. AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
56|. ASSERT(AfxGetThread() == NULL);
57|. pThreadState->m_pCurrentWinThread = this;
58|. ASSERT(AfxGetThread() == this);
59|. m_hThread = ::GetCurrentThread();
60|. m_nThreadID = ::GetCurrentThreadId();
61|.
62|. // initialize CWinApp state
63|. ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
64|. pModuleState->m_pCurrentWinApp = this;
65|. ASSERT(AfxGetApp() == this);
66|. …
67|. }
再看AfxWinInit函数
68|. BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
69|. LPTSTR lpCmdLine, int nCmdShow)
70|. {
71|. …
72|. // set resource handles
73|. AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
74|. pModuleState->m_hCurrentInstanceHandle = hInstance;
75|. pModuleState->m_hCurrentResourceHandle = hInstance;
76|.
77|. // fill in the initial state for the application
78|. CWinApp* pApp = AfxGetApp();
79|. if (pApp != NULL)
80|. {
81|. // Windows specific initialization (not done if no CWinApp)
82|. pApp->m_hInstance = hInstance;
83|. hPrevInstance; // Obsolete.
84|. pApp->m_lpCmdLine = lpCmdLine;
85|. pApp->m_nCmdShow = nCmdShow;
86|. pApp->SetCurrentHandles();
87|. }
88|.
89|. // initialize thread specific data (for main thread)
90|. if (!afxContextIsDLL)
91|. AfxInitThread();
92|.
93|. …
94|.
95|. return TRUE;
96|. }
这里不得不说明一下AfxGetThreadState函数。它也是一个全局变量的包装函数,这个全局变量是_afxThreadState,它是_AFX_THREAD_STATE的实例,在单线程程序中这个实例的意义不大,但在多线程条件下,它可是连接AFX_MODULE_STATE和当前线程的一个桥梁。相关定义如下:
97|. class _AFX_THREAD_STATE : public CNoTrackObject
98|. {
99|. public:
100|. _AFX_THREAD_STATE();
101|. virtual ~_AFX_THREAD_STATE();
102|.
103|. // override for m_pModuleState in _AFX_APP_STATE
104|. AFX_MODULE_STATE* m_pModuleState;
105|. AFX_MODULE_STATE* m_pPrevModuleState;
106|. };
因为线程与模块的对应关系是多对一的,一个模块可以有多个线程,但一个线程只能有一个模块(不是其线程入口所在的模块,而是拥有它的模块)
其中m_pModuleState的初始化过程在CWinThread的线程入口过程中:
107|. UINT APIENTRY _AfxThreadEntry(void* pParam)
108|. {
109|. _AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;
110|. …
111|. CWinThread* pThread = pStartup->pThread;
112|. CWnd threadWnd;
113|. TRY
114|. {
115|. // inherit parent's module state
116|. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
117|. pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;
118|. …
119|. }
120|. …
121|. }
也就是说在不起动新线程的Mfc程序中,m_pModuleState不会被赋值。其默认值为0。