1. 程式人生 > >MFC六大核心機制之一:MFC程式的初始化流程

MFC六大核心機制之一:MFC程式的初始化流程

1,手動編寫MFC
下面就是我們要手寫MFC的程式碼,

class CMyApp:public CWinApp
{
public:
	virtual BOOL InitInstance();
};
class CMainWnd:public CFrameWnd
{
public:
	CMainWnd();
};
CMyApp theApp;
BOOL CMyApp::InitInstance()
{
//建立視窗
	m_pMainWnd=new CMainWnd;
	m_pMainWnd->ShowWindow(m_nCmdShow);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}
CMainWnd::CMainWnd()
{
	Create(NULL,TEXT("Hell MFC"));
}

MFC程式的入口是WinMain而我們並沒有提供入口而上面這段程式卻能創建出一個窗口出來。
當我們沒有提供入口的時候,實際上MFC已經幫我準備了入口,對於這段程式執行在vc6.0上,按下F10即可進入到函式入口:
在這裡插入圖片描述
進入到AfxWinMain函式中:
在這裡插入圖片描述
這個就是MFC為我們準備好的入口,實際上已經做了很多的事情。
這裡面有幾個重要的函式:AfxGetThread,pThread->InitInstance,pThread->Run()
在AFXWIN.H中是這麼定義的:
CWinApp* AFXAPI AfxGetApp();
那麼AfxGetApp是怎麼獲取當前App的CWinApp類指標呢?
AfxGetApp是一個行內函數,其實現如下(在AFXWIN1.INL):
AFXWIN_INLINE CWinApp *AFXAPI AfxGetApp()
{ return afxCurrentWinApp;}
而afxCurrentWinApp是一個巨集,定義在AFXWIN.H中:
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
AfxGetModuleState返回的是一個:AFX_MODULE_STATE類的指標(AFXSTAT

.H):
AFX_MODULE_STATE* AFXAPI AfxGetModuleState();

在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
DWORD m_fRegisteredClasses; // flags for registered window classes

AFX_MODULE_STATE是在什麼時候進行的初始化呢?最可能就是在theApp初始化的時候,
theApp繼承了CWinApp,所以CWinApp的建構函式會執行。下面就是CWinApp建構函式的原始碼,建立了2個指標:AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE分別指向了CWinApp和它的父類。

CWinApp的建構函式
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
	if (lpszAppName != NULL)
		m_pszAppName = _tcsdup(lpszAppName);
	else
		m_pszAppName = NULL;

	// initialize CWinThread state   建立了一個AFX_MODULE_STATE指標
	AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
建立了一個AFX_MODULE_THREAD_STATE的指標
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
	m_hInstance = NULL;
	m_pszHelpFilePath = NULL;
	m_pszProfileName = NULL;
	m_pszRegistryKey = NULL;
	m_pszExeName = NULL;
	m_pRecentFileList = NULL;
	m_pDocManager = NULL;
	m_atomApp = m_atomSystemTopic = NULL;
	m_lpCmdLine = NULL;
	m_pCmdInfo = NULL;

	// initialize wait cursor state
	m_nWaitCursorCount = 0;
	m_hcurWaitCursorRestore = NULL;

	// initialize current printer state
	m_hDevMode = NULL;
	m_hDevNames = NULL;
	m_nNumPreviewPages = 0;     // not specified (defaults to 1)

	// initialize DAO state
	m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

	// other initialization
	m_bHelpMode = FALSE;
	m_nSafetyPoolSize = 512;        // default size
}

有一個知識點一定要知道:
在main函式中沒有寫任何程式,但是仍然會列印Hello出來

class BB
{
	void BB()
	{
		printf("Hello");
	}
};
BB b;
int main(int argc, char* argv[])
{
}

所以CMyApp theApp;會先於程式入口執行,初始化的時候會寫填寫好
AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE這兩個指標,於是我們可以考慮在記憶體中有一份AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE的全域性變數,不然AfxGetApp怎麼得到這些資料。

然後我們進入到pThread->InitInstance函式中就得到下面的函數了,為什麼會得到下面的函式呢,首先InitInstance是一個虛擬函式,被我們寫的子類重寫了,而pThread是Cwinapp的父類,cwinapp是Cmyapp的父類,虛擬函式被覆蓋了,所以呼叫的是cmyapp的InitInstance函式。
在這裡插入圖片描述
然後我們進入到pThread->Run()中,再進入到CWinThread::Run()中,就發現了我們非常熟悉的東西,訊息迴圈。
在這裡插入圖片描述
在這裡插入圖片描述