瑞星卡卡安全论坛

首页 » 技术交流区 » 系统软件 » MFC代码分析01:初探MFC程序初始化及运行
天下奇才 - 2008-9-28 10:34:00
对于MFC程序整个引导过程,可以归结为以下步骤:
_tWinMain  --> AfxWinMain  --> AfxWinInit -->  CWinThread::InitApplication  --> CWinThread::InitInstance  -->  CWinThread::Run

一个看似简单的向导式可视化编程,创建应用程序其实也并不简单!
首先,我们看看Windows编程中,最重要的一个函数,WinMain


引用:

extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

实际上,MFC的WinMain函数什么都没做,只是将控制权转向了AfxWinMain(带有Afx的函数是一组公有的函数)

很自然的,我们把目光转向了AfxWinMain


引用:

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_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;
}

总结而言,AfxWinMain进行了以下的动作:
获取当前运行线程对象指针(AfxGetThread())
获取应用程序实例指针(AfxGetApp())
初始化窗口
(CWinThread::InitApplication())
初始化CWinApp实例(CApp::InitInstance())  ->>此时显示窗口基本元素
运行(CWinApp::Run())

用户系统信息:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322)
天下奇才 - 2008-9-28 10:34:00
我们跟踪AfxWinMain()执行便可发现,在其中用到了多个Afx开头的函数进行引导。那么到底这些函数干了些什么?凭什么一个应用程序产生了呢?

我们将注意力转向AfxGetThread(),此函数返回一运行线程对象指针


引用:

CWinThread* AFXAPI AfxGetThread()
{
// check for current thread in module thread state
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
CWinThread* pThread = pState->m_pCurrentWinThread;
return pThread;
}

实际上此函数只进行了一下行为:
获取一AFX_MODULE_THREAD_STATE结构(AfxGetMainWnd())
获取当前线程指针(AFX_MODULE_THREAD_STATE::m_pCurrentWinThread),返回
期间最重要的操作,便是调用了AfxGetMainWnd函数。实际上AfxGetMainWnd函数中,控制权曾一度转交AfxGetModuleState。AfxGetModuleState完成的工作也就是从本地全局对象中获取数据。

下一步,我们看到,就是通过AfxGetApp()获取应用程序实例指针。接着出现了一个非常非常重要的函数,那便是AfxWinInit。看名字这么长,就知道这个函数非同寻常!!!首先,我们给出它的整个执行过程:
获取全局模块数据对象(AfxGetModuleState())
获取当前实例与资源句柄
获取应用程序实例指针(AfxGetApp())
初始化应用程序实例对象
检查是否DLL(AfxGetModuleState()->m_bDLL),不是则初始化线程(AfxInitThread())
获取user32.dll模块句柄,获取NotifyWinEvent函数指针


引用:

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;
  hPrevInstance; // Obsolete.
  pApp->m_lpCmdLine = lpCmdLine;
  pApp->m_nCmdShow = nCmdShow;
  pApp->SetCurrentHandles();
}
// initialize thread specific data (for main thread)
if (!afxContextIsDLL)
  AfxInitThread();
// Initialize CWnd::m_pfnNotifyWinEvent
HMODULE hModule = ::GetModuleHandle(_T("user32.dll"));
if (hModule != NULL)
{
  CWnd::m_pfnNotifyWinEvent = (CWnd::PFNNOTIFYWINEVENT)::GetProcAddress(hModule, "NotifyWinEvent");
}
return TRUE;
}

值得一提的是其中的初始华线程过程:AfxInitThread()。它进行的主要操作,就是一个消息挂钩。


引用:

CWinThread* AFXAPI AfxGetThread()
{
// check for current thread in module thread state
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
CWinThread* pThread = pState->m_pCurrentWinThread;
return pThread;
}

这就是消息处理的真正所在!!

后面进行的Run操作,最吸引我眼球的莫过于其中的消息循环,各位看看是不是很熟悉呢?


引用:

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));
}
}
天下奇才 - 2008-9-28 10:57:00
实际上作为一个程序,MFC由向导创建的代码,并不是不存在WinMain函数,也不是不存在消息循环。它和一般的应用程序一样,都是在一样的路中走出不一样的自我。
文物2 - 2008-9-28 11:23:00
看的头晕脑涨的:default7:
sdxianchao - 2010-4-24 22:58:00
哥们受教了,我在网上找了很久,你这篇文章讲MFC的启动最清楚。
1
查看完整版本: MFC代码分析01:初探MFC程序初始化及运行