一、程序的入口函数介绍
程序代码都有一个主函数,它是整个项目的第一个入口点,其它函数直接或间接被它调用。VC项目前后出现如下六个入口函数:main、wmain、_tmain、WinMain、 wWinMain、_tWinMain,以下分别介绍它们的用法。
1、介绍它们的作用,参考如下:
(1)、main()是WINDOWS的控制台程序(32位)或DOS程序(16位);
(2)、wmain()是UNICODE版本的main();
(3)、_tmain()是个宏,若是UNICODE,则它为wmain();否则为main()。
(4)、WinMain()是WINDOWS的GUI程序;
(5)、wWinMain是UNICODE版本的WinMain ();
(6)、_tWinMain是个宏,若是UNICODE,则它为wWinMain ();否则为WinMain()。
2、这些入口函数的理解,参考如下:
基本的入口函数是main(),其余的无非是加了一些前缀而也,以下分别说明这个问题:
(1)、Win前缀
前三者不含“Win”,为控制台程序或DOS程序的入口函数;后三者含“Win”,为窗口应用程序的入口函数。
(2)、w前缀
该前缀为UNICODE版本的标志。wmain()是UNICODE版本的main(),wWinMain是UNICODE版本的WinMain ()。
(3)、_t前缀
该前缀为复合版本的标志。_tmain()是个宏,若是UNICODE,则它为wmain();否则为main();_tWinMain是个宏,若是UNICODE,则它为wWinMain ();否则为WinMain()。
_tmain、_tWinMain定义在<tchar.h>文件,参考如下:
#ifdef _UNICODE
#define _tmain wmain
#define _tWinMain wWinMain
#else /* ndef _UNICODE */
#define _tmain main
#define _tWinMain WinMain
#endif
二、寻找MFC程序程序的入口函数
我们知道在WIN32 API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数。而在MFC程序中,我们能不能找到类似于WinMain这样的程序入口?
1、在appcore.cpp文件找到疑似入口函数(_tWinMain)
在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\appcore.cpp文件,有如下代码:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
2、AfxWinMain()的代码
在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\winmain.cpp文件,有如下代码:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ 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_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)
{
TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
3、AfxWinMain()的主要调用过程
可以看到,在这里面先对窗口进行了初始化,再对线程和app对象进行了初始化,即依次对三个函数的调用:
pApp->InitApplication();
pThread->InitInstance();
pThread->Run();
在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\appcore.cpp文件,有如下代码:
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;
LoadSysPolicies();
return TRUE;
}
在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\ thrdcore.cpp文件,有如下代码:
BOOL CWinThread::InitInstance()
{
ASSERT_VALID(this);
return FALSE; // by default don‘t enter run loop
}
在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\ thrdcore.cpp文件,有如下代码:
int CWinThread::Run()
{
ASSERT_VALID(this);
_AFX_THREAD_STATE* pState = AfxGetThreadState();
// 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(&(pState->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))
if (IsIdleMessage(&(pState->m_msgCur)))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
}
}
三、主要过程总结
可以看到在CWinThread::Run()进入了消息循环,直到收到WM_QUIT消息,退出消息循环。
CWinApp类的Run(其实它是父类CWinThread的成员)成员函数中的消息循环检索由各种事件生成的排队消息。例如,当用户单击鼠标时,Windows会发送一些与鼠标相关的消息,例如鼠标左键被按下时发送WM_LBUTTONDOWN消息,鼠标左键被释放时发送WM_LBUTTONUP消息。框架的应用程序消息循环实现将消息分派到适当的窗口。
Run获取并分派Windows消息,直到应用程序接收到一个WM_QUIT消息。如果应用程序的消息队列当前不包含消息,则运行调用OnIdle来执行空闲时间处理。传入的消息将转到PreTranslateMessage成员函数进行特殊处理,然后转到Windows函数TranslateMessage进行标准键盘翻译。最后,调用DispatchMessage Windows函数。
Run很少被覆盖,但是您可以覆盖它以提供特殊的行为。
在消息运行结束,用户按下关闭按钮后,操作系统向程序发送WM_CLOSE消息,默认状况下程序调用DestoryWindow并且发送WM_DESTORY消息,应用程序接受到这个消息以后的默认操作是调用PostQuitMessage函数,由这个函数发送WM_QUIT消息。当程序对象接受到WM_QUIT消息后消息循环结束,由AfxWinMain函数调用AfxTerm函数清理程序使用过的资源并且结束整个程序。
在appcore.cpp文件中,我们能够找到MFC程序的入口函数是_tWinMain,但至于怎么调用的呢?这个问题是找不到的,这个由编译器内部自动完成了。
可见,在MFC程序中,我们不能找到类似于WinMain这样的程序入口。