MFC初始化过程
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)。下面只列出与初始化过程相关的部分:
class AFX_MODULE_STATE : public CNoTrackObject
{
public:
#ifdef _AFXDLL
AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
BOOL bSystem = FALSE);
#else
explicit AFX_MODULE_STATE(BOOL bDLL);
#endif
~AFX_MODULE_STATE();
CWinApp* m_pCurrentWinApp;
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;
LPCTSTR m_lpszCurrentAppName;
BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
BYTE m_bReserved[2]; // padding
// define thread local portions of module state
CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;
};
函数AfxGetApp返回的正是_afxBaseModuleStat中m_pCurrentWinApp 成员。
_AFXDLL部分与MFC Regular Dll相关,暂不讨论。而AFX_MODULE_STATE秉承MFC的一贯原则,构造函数只保证了数据结构的有效性,而未对数据内容做出任何保证。因此,_ afxBaseModuleState构造后,其内容还是未知的。仅从成员可以知道,该类表示CWinApp所在模块(EXE)。而它的成员m_thread则表达了该模块中线程的状态(其实际类型为AFX_MODULE_THREAD_STATE)。该类的相关定义如下:
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
};
AfxGetThread函数正是由_afxBaseModuleState取得取了AFX_MODULE_THREAD_STATE中的m_pCurrentThread成员。
下面是CCmdTarget,CWinThread和CWinApp构造函数中对以上成员变量初始化的过程。
CCmdTarget
无
CWinThread
CWinThread::CWinThread()
{
…
CommonConstruct();
}
void CWinThread::CommonConstruct()
{
…
_AFX_THREAD_STATE* pState = AfxGetThreadState();
// initialize message pump
#ifdef _DEBUG
pState->m_nDisablePumpCount = 0;
#endif
pState->m_msgCur.message = WM_NULL;
pState->m_nMsgLast = WM_NULL;
…
}
CWinApp
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
…
// 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);
…
}
再看AfxWinInit函数
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
…
// 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();
if (pApp != NULL)
{
// Windows specific initialization (not done if no CWinApp)
pApp->m_hInstance = hInstance;
hPrevInstance; // Obsolete.
pApp->m_lpCmdLine = lpCmdLine;
pApp->m_nCmdShow = nCmdShow;
pApp->SetCurrentHandles();
}
// initialize thread specific data (for main thread)
if (!afxContextIsDLL)
AfxInitThread();
…
return TRUE;
}
这里不得不说明一下AfxGetThreadState函数。它也是一个全局变量的包装函数,这个全局变量是_afxThreadState,它是_AFX_THREAD_STATE的实例,在单线程程序中这个实例的意义不大,但在多线程条件下,它可是连接AFX_MODULE_STATE和当前线程的一个桥梁。相关定义如下:
class _AFX_THREAD_STATE : public CNoTrackObject
{
public:
_AFX_THREAD_STATE();
virtual ~_AFX_THREAD_STATE();
// override for m_pModuleState in _AFX_APP_STATE
AFX_MODULE_STATE* m_pModuleState;
AFX_MODULE_STATE* m_pPrevModuleState;
};
因为线程与模块的对应关系是多对一的,一个模块可以有多个线程,但一个线程只能有一个模块(不是其线程入口所在的模块,而是拥有它的模块)
其中m_pModuleState的初始化过程在CWinThread的线程入口过程中:
UINT APIENTRY _AfxThreadEntry(void* pParam)
{
_AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;
…
CWinThread* pThread = pStartup->pThread;
CWnd threadWnd;
TRY
{
// inherit parent's module state
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;
…
}
…
}
也就是说在不起动新线程的Mfc程序中,m_pModuleState不会被赋值。其默认值为0。
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)。下面只列出与初始化过程相关的部分:
class AFX_MODULE_STATE : public CNoTrackObject
{
public:
#ifdef _AFXDLL
AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
BOOL bSystem = FALSE);
#else
explicit AFX_MODULE_STATE(BOOL bDLL);
#endif
~AFX_MODULE_STATE();
CWinApp* m_pCurrentWinApp;
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;
LPCTSTR m_lpszCurrentAppName;
BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
BYTE m_bReserved[2]; // padding
// define thread local portions of module state
CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;
};
函数AfxGetApp返回的正是_afxBaseModuleStat中m_pCurrentWinApp 成员。
_AFXDLL部分与MFC Regular Dll相关,暂不讨论。而AFX_MODULE_STATE秉承MFC的一贯原则,构造函数只保证了数据结构的有效性,而未对数据内容做出任何保证。因此,_ afxBaseModuleState构造后,其内容还是未知的。仅从成员可以知道,该类表示CWinApp所在模块(EXE)。而它的成员m_thread则表达了该模块中线程的状态(其实际类型为AFX_MODULE_THREAD_STATE)。该类的相关定义如下:
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
};
AfxGetThread函数正是由_afxBaseModuleState取得取了AFX_MODULE_THREAD_STATE中的m_pCurrentThread成员。
下面是CCmdTarget,CWinThread和CWinApp构造函数中对以上成员变量初始化的过程。
CCmdTarget
无
CWinThread
CWinThread::CWinThread()
{
…
CommonConstruct();
}
void CWinThread::CommonConstruct()
{
…
_AFX_THREAD_STATE* pState = AfxGetThreadState();
// initialize message pump
#ifdef _DEBUG
pState->m_nDisablePumpCount = 0;
#endif
pState->m_msgCur.message = WM_NULL;
pState->m_nMsgLast = WM_NULL;
…
}
CWinApp
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
…
// 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);
…
}
再看AfxWinInit函数
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
…
// 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();
if (pApp != NULL)
{
// Windows specific initialization (not done if no CWinApp)
pApp->m_hInstance = hInstance;
hPrevInstance; // Obsolete.
pApp->m_lpCmdLine = lpCmdLine;
pApp->m_nCmdShow = nCmdShow;
pApp->SetCurrentHandles();
}
// initialize thread specific data (for main thread)
if (!afxContextIsDLL)
AfxInitThread();
…
return TRUE;
}
这里不得不说明一下AfxGetThreadState函数。它也是一个全局变量的包装函数,这个全局变量是_afxThreadState,它是_AFX_THREAD_STATE的实例,在单线程程序中这个实例的意义不大,但在多线程条件下,它可是连接AFX_MODULE_STATE和当前线程的一个桥梁。相关定义如下:
class _AFX_THREAD_STATE : public CNoTrackObject
{
public:
_AFX_THREAD_STATE();
virtual ~_AFX_THREAD_STATE();
// override for m_pModuleState in _AFX_APP_STATE
AFX_MODULE_STATE* m_pModuleState;
AFX_MODULE_STATE* m_pPrevModuleState;
};
因为线程与模块的对应关系是多对一的,一个模块可以有多个线程,但一个线程只能有一个模块(不是其线程入口所在的模块,而是拥有它的模块)
其中m_pModuleState的初始化过程在CWinThread的线程入口过程中:
UINT APIENTRY _AfxThreadEntry(void* pParam)
{
_AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;
…
CWinThread* pThread = pStartup->pThread;
CWnd threadWnd;
TRY
{
// inherit parent's module state
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;
…
}
…
}
也就是说在不起动新线程的Mfc程序中,m_pModuleState不会被赋值。其默认值为0。
浙公网安备 33010602011771号