例子是一個(gè)mfc的對(duì)話框,用vc調(diào)試器查看了一個(gè)程序從生成初始化到接受消息的流程。從產(chǎn)生到結(jié)束的基本流程是這樣的:
KERNEL32->WinMainCRTStartup()->_tWinMain(開始)->AfxWinMain(開始)->AfxGetThread()->AfxWinInit()->InitApplication()->InitInstance()->DoModal()->RunModalLoop()->ExitInstance()->AfxWinMain(結(jié)束)->_tWinMain(結(jié)束)
1、KERNEL32
kernel32.dll是Windows9x/Me中非常重要的32位動(dòng)態(tài)鏈接庫文件,屬于內(nèi)核級(jí)文件。它控制著系統(tǒng)的內(nèi)存管理、數(shù)據(jù)的輸入輸出操作和中斷處理,當(dāng)Windows啟動(dòng)時(shí),kernel32.dll就駐留在內(nèi)存中特定的寫保護(hù)區(qū)域,使別的程序無法占用這個(gè)內(nèi)存區(qū)域。
2、WinMainCRTStartup()函數(shù)
程序默認(rèn)的基地址(EXE文件默認(rèn)為0x400000,DLL默認(rèn)為x10000000),操作系統(tǒng)裝載一個(gè)程序時(shí)總是試著先從這個(gè)基地址開始。一般Win32的程序,EXE的入口為WinMain,DLL的入口為DllEntryPoint。默認(rèn)情況下,通過一個(gè)C的運(yùn)行時(shí)庫函數(shù)來實(shí)現(xiàn):控制臺(tái)程序采用mainCRTStartup (或wmainCRTStartup)去調(diào)用程序的main (或wmain)函數(shù);Windows程序采用WinMainCRTStartup (或 wWinMainCRTStartup)調(diào)用程序的WinMain (或 wWinMain,必須采用__stdcall調(diào)用約定);DLL采用_DllMainCRTStartup調(diào)用DllMain函數(shù)(必須采用__stdcall調(diào)用約定)。
它負(fù)責(zé):
* 檢索指向新進(jìn)程的完整命令行指針;
* 檢索指向新進(jìn)程的環(huán)境變量的指針;
* 對(duì)c/c++運(yùn)行時(shí)的全局變量進(jìn)行初始化;
* 對(duì)c運(yùn)行期的內(nèi)存單元分配函數(shù)(比如malloc,calloc)和其他低層I/O例程使用的內(nèi)存棧 進(jìn)行初始化。
* 為C++的全局和靜態(tài)類調(diào)用構(gòu)造函數(shù)。
當(dāng)這些初始化工作完成后,該啟動(dòng)函數(shù)就調(diào)用wWinMain函數(shù)進(jìn)入應(yīng)用程序的執(zhí)行。
當(dāng)wWinMain函數(shù)執(zhí)行完畢返回時(shí),wWinMainCRTStartup啟動(dòng)函數(shù)就調(diào)用c運(yùn)行期的exit()函
數(shù),將返回值(nMainRetVal)傳遞給它。
之后exit()便開始收尾工作:
* 調(diào)用由_onexit()函數(shù)調(diào)用和注冊(cè)的任何函數(shù)。
* 為C++的全局和靜態(tài)類調(diào)用析構(gòu)函數(shù);
* 調(diào)用操作系統(tǒng)的ExitProcess函數(shù),將nMainRetVal傳遞給它,這使得操作系統(tǒng)能夠撤銷 進(jìn)程并設(shè)置它的exit 代碼。
最小體積的win32程序:(不要編譯缺省庫)
#pragma comment (linker, "/SUBSYSTEM:WINDOWS")
#pragma comment (linker, "/NODEFAULTLIB")
int WinMainCRTStartup()
{
return 0;
}
3、WinMain()函數(shù)
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
4、AfxWinMain()函數(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)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
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)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
5、AfxGetThread()函數(shù)
CWinThread* AFXAPI AfxGetThread()
{
// check for current thread in module thread state
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
CWinThread* pThread = pState->m_pCurrentWinThread;
// if no CWinThread for the module, then use the global app
if (pThread == NULL)
pThread = AfxGetApp();
return pThread;
}
6、AfxWinInit()函數(shù)
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
// handle critical errors and avoid Windows message boxes
SetErrorMode(SetErrorMode(0) |
SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
// 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;
pApp->m_hPrevInstance = hPrevInstance;
pApp->m_lpCmdLine = lpCmdLine;
pApp->m_nCmdShow = nCmdShow;
pApp->SetCurrentHandles();
}
// initialize thread specific data (for main thread)
if (!afxContextIsDLL)
AfxInitThread();
return TRUE;
}
7、InitApplication() 函數(shù)
BOOL CMy1App::InitApplication()
{
// TODO: Add your specialized code here and/or call the base class
AfxMessageBox("InitApplication");
return CWinApp::InitApplication();
}
BOOL CWinApp::InitApplication()
{
if (CDocManager::pStaticDocManager != NULL)
{
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager;
CDocManager::pStaticDocManager = NULL;
}
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager::bStaticInit = FALSE;
return TRUE;
}
8、InitInstance()函數(shù)
AfxWinMain函數(shù)里面的if (!pThread->InitInstance())會(huì)調(diào)用程序CMy1App的InitInstance函數(shù):
BOOL CMy1App::InitInstance()
{
AfxEnableControlContainer();
AfxMessageBox("InitInstance");
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CMy1Dlg dlg;//調(diào)用CMy1Dlg的構(gòu)造函數(shù)
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
9、AfxWinMain()函數(shù)里面的主要的循環(huán)體,在這里:
if (!pThread->InitInstance())//主要是模式對(duì)話框調(diào)用,對(duì)話框關(guān)閉以后InitInstance函數(shù)才會(huì)結(jié)束
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();//非模式對(duì)話框和一般程序調(diào)用這個(gè)循環(huán)
InitInstance函數(shù)調(diào)用了dlg.DoModal()函數(shù),以下是DoModal()函數(shù):
int CDialog::DoModal()
{
// can be constructed with a resource template or InitModalIndirect
ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||
m_lpDialogTemplate != NULL);
// load resource as necessary
LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
HGLOBAL hDialogTemplate = m_hDialogTemplate;
HINSTANCE hInst = AfxGetResourceHandle();
if (m_lpszTemplateName != NULL)
{
hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
hDialogTemplate = LoadResource(hInst, hResource);
}
if (hDialogTemplate != NULL)
lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);
// return -1 in case of failure to load the dialog template resource
if (lpDialogTemplate == NULL)
return -1;
// disable parent (before creating dialog)
HWND hWndParent = PreModal();
AfxUnhookWindowCreate();
BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent, FALSE);
bEnableParent = TRUE;
}
TRY
{
// create modeless dialog
AfxHookWindowCreate(this);
if (CreateDlgIndirect(lpDialogTemplate,
CWnd::FromHandle(hWndParent), hInst))//創(chuàng)建對(duì)話框的窗口
{
if (m_nFlags & WF_CONTINUEMODAL)
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG)
dwFlags |= MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);//這里是真正的循環(huán)RunModalLoop
}
// hide the window before enabling the parent, etc.
if (m_hWnd != NULL)
SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
}
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
m_nModalResult = -1;
}
END_CATCH_ALL
if (bEnableParent)
::EnableWindow(hWndParent, TRUE);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
// destroy modal window
DestroyWindow();
PostModal();
// unlock/free resources as necessary
if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
UnlockResource(hDialogTemplate);
if (m_lpszTemplateName != NULL)
FreeResource(hDialogTemplate);
return m_nModalResult;
}
模式對(duì)話框調(diào)用的循環(huán)函數(shù)RunModalLoop()函數(shù)如下:
int CWnd::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); // window must be created
ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG* pMsg = &AfxGetThread()->m_msgCur;
// acquire and dispatch messages until the modal state is done
for (;;)
{
ASSERT(ContinueModal());
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// call OnIdle while in bIdle state
if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
{
// send WM_ENTERIDLE to the parent
::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
{
// stop idle processing next time
bIdle = FALSE;
}
}
// phase2: pump messages while available
do
{
ASSERT(ContinueModal());
// pump message, but quit on WM_QUIT
if (!AfxGetThread()->PumpMessage())//主要在這里循環(huán)
{
AfxPostQuitMessage(0);
return -1;
}
// show the window when certain special messages rec'd
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())
goto ExitModal;
// reset "no idle" state after pumping "normal" message
if (AfxGetThread()->IsIdleMessage(pMsg))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}
一般程序調(diào)用的循環(huán)函數(shù)Run函數(shù)如下:
int CWinThread::Run()
{
ASSERT_VALID(this);
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
// phase2: pump messages while available
do
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // not reachable
}
==========
我認(rèn)為是更加完整的應(yīng)該是_DllMainCRTStartup->
WinMainCRTStartup(void)->()->_tWinMain(開始)->AfxWinMain(開始)->AfxGetThread()->AfxWinInit()->InitApplication()->InitInstance()->DoModal()->RunModalLoop()->ExitInstance()->AfxWinMain(結(jié)束)->_tWinMain(結(jié)束)
參考http://www.shnenglu.com/citywanderer/articles/8716.html
posted on 2009-10-01 22:51
鷹擊長空 閱讀(1594)
評(píng)論(0) 編輯 收藏 引用