MFC 學(xué)習(xí)筆記 2 WinMain函數(shù)的調(diào)用過(guò)程
MFC是一個(gè)類庫(kù), 是別人寫好的一套源碼,實(shí)現(xiàn)了對(duì)系統(tǒng)API調(diào)用的封裝,
與其辛苦學(xué)習(xí)使用別人設(shè)計(jì)的類庫(kù),不如好好學(xué)習(xí)一下其實(shí)現(xiàn)原理,
一個(gè)EXE窗口程序運(yùn)行后,由系統(tǒng)載入調(diào)用的函數(shù)過(guò)程如下:
一、調(diào)用VC運(yùn)行庫(kù)文件crtexe.c中的WinMainCRTStartup函數(shù)
大致內(nèi)容整理如下:
主要的功能是設(shè)置命令行參數(shù)和窗口啟動(dòng)的一些參數(shù)。
void?WinMainCRTStartup(void?) { int?argc;???/*?three?standard?arguments?to?main?*/ _TSCHAR?**argv; _TSCHAR?**envp; int?mainret; _TUCHAR?*lpszCommandLine; STARTUPINFO?StartupInfo; _startupinfo????startinfo; __try?{ /* *?Set?__app_type?properly */ ? __set_app_type(_GUI_APP);? __onexitbegin?=?__onexitend?=?(_PVFV?*)(-1);?? _adjust_fdiv?=?*?_imp___adjust_fdiv;? _setargv();? if?(?!__defaultmatherr?) __setusermatherr(_matherr); _setdefaultprecision();? _initterm(?__xi_a,?__xi_z?);? startinfo.newmode?=?_newmode; __getmainargs(&argc,?&argv,?&envp,?_dowildcard,?&startinfo); _initterm(?__xc_a,?__xc_z?);? lpszCommandLine?=?(unsigned?char?*)_acmdln; if?(?*lpszCommandLine?==?DQUOTECHAR?)?{ while?(?*++lpszCommandLine?&&?(*lpszCommandLine ????????????????if?(?*lpszCommandLine?==?DQUOTECHAR?) ????????????????????lpszCommandLine++; } else?{ while?(*lpszCommandLine?>?SPACECHAR) lpszCommandLine++; } while?(*lpszCommandLine?&&?(*lpszCommandLine?<=?SPACECHAR))?{ lpszCommandLine++; } StartupInfo.dwFlags?=?0; GetStartupInfo(?&StartupInfo?); mainret?=?WinMain( GetModuleHandle(NULL), NULL, lpszCommandLine, StartupInfo.dwFlags?&?STARTF_USESHOWWINDOW ??StartupInfo.wShowWindow :?SW_SHOWDEFAULT ); __initenv?=?envp; mainret?=?main(argc,?argv,?envp); exit(mainret); } __except?(?_XcptFilter(GetExceptionCode(),?GetExceptionInformation())?) { /* *?Should?never?reach?here */ _exit(?GetExceptionCode()?); }?/*?end?of?try?-?except?*/ }
二、調(diào)用WinMain函數(shù)
winmain是一個(gè)函數(shù)聲明,每個(gè)程序中都要自己實(shí)現(xiàn),如果自己沒(méi)有實(shí)現(xiàn)這個(gè)函數(shù),就會(huì)使用MFC庫(kù)中實(shí)現(xiàn),
所以每個(gè)Win32程序,必須要有一個(gè)winmain函數(shù),因?yàn)閂C運(yùn)行庫(kù)中的啟動(dòng)函數(shù)WinMainCRTStartup需要調(diào)用這個(gè)實(shí)現(xiàn)函數(shù)。
如MFC中也有這個(gè)函數(shù)聲明
extern?"C"?int?WINAPI _tWinMain(HINSTANCE?hInstance,?HINSTANCE?hPrevInstance, LPTSTR?lpCmdLine,?int?nCmdShow) { //?call?shared/exported?WinMain return?AfxWinMain(hInstance,?hPrevInstance,?lpCmdLine,?nCmdShow); }
三、MFC中的AfxWinMain調(diào)用
MFC程序也是先調(diào)用WinMain,然后轉(zhuǎn)到MFC的AfxWinMain函數(shù)。
///////////////////////////////////////////////////////////////////////////// //?export?WinMain?to?force?linkage?to?this?module extern?int?AFXAPI?AfxWinMain(HINSTANCE?hInstance,?HINSTANCE?hPrevInstance, LPTSTR?lpCmdLine,?int?nCmdShow); extern?"C"?int?WINAPI _tWinMain(HINSTANCE?hInstance,?HINSTANCE?hPrevInstance, LPTSTR?lpCmdLine,?int?nCmdShow) { //?call?shared/exported?WinMain return?AfxWinMain(hInstance,?hPrevInstance,?lpCmdLine,?nCmdShow); }
四、AfxWinMain函數(shù)調(diào)用CWinApp中的函數(shù)
int?AFXAPI?AfxWinMain(HINSTANCE?hInstance,?HINSTANCE?hPrevInstance, LPTSTR?lpCmdLine,?int?nCmdShow) { ASSERT(hPrevInstance?==?NULL); int?nReturnCode?=?-1; CWinThread*?pThread?=?AfxGetThread(); CWinApp*?pApp?=?AfxGetApp(); //?AFX?internal?initialization if?(!AfxWinInit(hInstance,?hPrevInstance,?lpCmdLine,?nCmdShow)) goto?InitFailure; //?App?global?initializations?(rare) if?(pApp?!=?NULL?&&?!pApp->InitApplication()) goto?InitFailure; //?Perform?specific?initializations if?(!pThread->InitInstance()) { if?(pThread->m_pMainWnd?!=?NULL) { TRACE(traceAppMsg,?0,?"Warning:?Destroying?non-NULL?m_pMainWndn"); 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; }
在AfxWinMain函數(shù),扯到好幾個(gè)init**初始化函數(shù),其中pThread->InitInstance()函數(shù),就是MFC向?qū)е猩蒀MyApp::Initstance之類
在這里就可以開(kāi)始創(chuàng)建窗口,現(xiàn)在可以開(kāi)始工作了。
BOOL?CTEST1App::InitInstance() { CWinApp::InitInstance();? CTEST1Dlg?dlg; m_pMainWnd?=?&dlg; INT_PTR?nResponse?=?dlg.DoModal(); ? return?nResponse; }
這樣一個(gè)MFC程序的來(lái)龍去脈,就是這幾個(gè)主要的函數(shù)實(shí)現(xiàn)的。