MFC内部运行来龙去脉追踪

来源:互联网 发布:js转化日期yyyymmdd 编辑:程序博客网 时间:2024/05/17 04:43

MFC内部运行来龙去脉追踪

1.全局对象theApp先于WinMain函数构造,而theApp是一个派生类的对象,故先调用基类CWinApp的构造函数,再调用派生类对象的构造函数。CWinApp的构造函数定义于APPCORE.CPP文件中

CWinApp::CWinApp(LPCTSTR lpszAppName)

{

 if (lpszAppName != NULL)

         m_pszAppName = _tcsdup(lpszAppName);

     else

      m_pszAppName = NULL;

 // initialize CWinThread state
     AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

     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
}

CWinApp构造函数主要完成this指针的赋值,将全局对象theAppthis指针赋值给全局唯一实例。该构造函数有一参数,我们在默认调用的时候却没有指定参数,其实这是因为有默认值,

追踪AFXWIN.h头文件查看CWinApp类的定义可知。

class CWinApp : public CWinThread
{

     DECLARE_DYNAMIC(CWinApp)

public:

// Constructor

     CWinApp(LPCTSTR lpszAppName = NULL);     // app name defaults to EXE name

   ......

接着调用我们自己派生类的构造函数,我们可以做一些数据成员的初始化操作。

CHelloMFCApp::CHelloMFCApp()
{
 // TODO: add construction code here,
 // Place all significant initialization in InitInstance
}

 

2.全局对象之后即是WinMain函数的调用,在MFC中对WinMain进行了封装。所以在文件中查找WinMain是找不到的。可以在源文件的class CAboutDlg : public CDialog这一行加上断点,F5运行,程序停在了

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

 LPTSTR lpCmdLine, int nCmdShow)

{

 // call shared/exported WinMain
     return
AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

代码处,而同时可以看到该代码位于APPMODUL.cpp中。说明程序运行时加载了该函数,有点像我们的WinMain函数。go to definition可以看到

#define _tWinMain   WinMain_tWinMain正是我们的WinMain

而为什么是_tWinMain而不是WinMain执行,这主要是MFC做了手脚,在MFC开始运行时就运行_tWinMain函数。其中又调用了AfxWinMain函数。在MFC源代码中查找一下AfxWinMain,在WINMAIN.cpp中可以找到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)

      {

           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;

}

稍加整理,可看到AfxWinMain主要做些什么事:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)

{

     int nReturnCode = -1;

 CWinApp* pApp = AfxGetApp();

     AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

 pApp->InitApplication();

     pApp->InitInstance();

 nReturnCode = pApp->Run();

 AfxWinTerm();

     return nReturnCode;

}

APPINIT.cpp中查看AfxWinInit的实现如下:

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;

}

void AFXAPI AfxInitThread()

{

     if (!afxContextIsDLL)

     {

  // set message filter proc

          _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();

          ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
          pThreadState->m_hHookOldMsgFilter=
::SetWindowsHookEx(WH_MSGFILT         ER, _AfxMsgFilterHook, NULL, ::GetCurrentThreadId());

#ifndef _AFX_NO_CTL3D_SUPPORT

  // intialize CTL3D for this thread

          _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;

         if (pCtl3dState->m_pfnAutoSubclass != NULL)

             (*pCtl3dState->m_pfnAutoSubclass)(AfxGetInstanceHandle());

  // allocate thread local _AFX_CTL3D_THREAD just for automatic termination
          _AFX_CTL3D_THREAD* pTemp = _afxCtl3dThread;

          pTemp;  // avoid unused warning

#endif

     }

}

 

AfxInitThread函数利用钩子函数将消息映射机制引入MFCMessage Map中,然后再回到默认的DefWindowProc。而AfxWinInit也主要做些初始化工作,完成一些初始细节配置。之后是pApp->Application()调用了,由于派生类没有改写,故调用基类CWinApp::Application(),回到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;

     return TRUE;

}

可以看到主要做些内部管理。然后是pApp->InitInstance()调用,派生类进行了改写,所以调用的是派生类的InitInstance(),如下:

BOOL CHelloMFCApp::InitInstance()

{

     AfxEnableControlContainer();

 // 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

 // Change the registry key under which our settings are stored.
 // TODO: You should modify this string to be something appropriate
 // such as the name of your company or organization.
         SetRegistryKey(_T("Local AppWizard-Generated Applications"));

         LoadStdProfileSettings();  // Load standard INI file options (including MRU)

 // Register the application's document templates.  Document templates
 //  serve as the connection between documents, frame windows and views.

 CMultiDocTemplate* pDocTemplate;

 pDocTemplate = new CMultiDocTemplate(

 IDR_HELLOMTYPE,

 RUNTIME_CLASS(CHelloMFCDoc),

 RUNTIME_CLASS(CChildFrame), // custom MDI child frame

 RUNTIME_CLASS(CHelloMFCView));

 AddDocTemplate(pDocTemplate);

 // create main MDI Frame window
   
CMainFrame* pMainFrame = new CMainFrame;

    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

         return FALSE;

    m_pMainWnd = pMainFrame;

 // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);

 // Dispatch commands specified on the command line
    if (!ProcessShellCommand(cmdInfo))
         return FALSE;

 // The main window has been initialized, so show and update it.
    pMainFrame->ShowWindow(m_nCmdShow);
    pMainFrame->UpdateWindow();

 return TRUE;
}

 

在派生类的InitInstance函数中产生了一个CMainFrame窗口对象,故先调用基类CMDIFrameWnd的构造函数,CMDIFrameWnd的基类是CFrameWnd,故调用CFrameWnd的构造函数,在WinFrm.cpp文件中:

CFrameWnd::CFrameWnd()

{

     ASSERT(m_hWnd == NULL);

     m_nWindow = -1;                 // unknown window ID

     m_bAutoMenuEnable = TRUE;       // auto enable on by default

     m_lpfnCloseProc = NULL;

     m_hMenuDefault = NULL;

     m_hAccelTable = NULL;

     m_nIDHelp = 0;
     m_nIDTracking = 0;

     m_nIDLastMessage = 0;

     m_pViewActive = NULL;

     m_cModalStack = 0;              // initialize modality support

     m_phWndDisable = NULL;

     m_pNotifyHook = NULL;

     m_hMenuAlt = NULL;

     m_nIdleFlags = 0;               // no idle work at start

 m_rectBorder.SetRectEmpty();

     m_bHelpMode = HELP_INACTIVE;    // not in Shift+F1 help mode
 m_dwPromptContext = 0;

 m_pNextFrameWnd = NULL;         // not in list yet

     m_bInRecalcLayout = FALSE;
 m_pFloatingFrameClass = NULL;
 m_nShowDelay = -1;              // no delay pending

 AddFrameWnd();
}

一直追踪到基类CWndCCmdTargetCObject都没有发现产生窗口(Create)的操作,当然在产生窗口之前首先要注册窗口。其实Create的调用是在pMainFrame->LoadFrame(IDR_MAINFRAME中完成的。即CFrameWnd::LoadFrame()

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
 CWnd* pParentWnd, CCreateContext* pContext)
{

 // only do this once
     ASSERT_VALID_IDR(nIDResource);
     ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

     m_nIDHelp = nIDResource;    // ID for help context (+HID_BASE_RESOURCE)

     CString strFullString;
     if (strFullString.LoadString(nIDResource))
          AfxExtractSubString(m_strTitle, strFullString, 0);    // first sub-string

     VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

 // attempt to create the window
     LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
     LPCTSTR lpszTitle = m_strTitle;
     if (!
Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
          pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))

     {
          return FALSE;   // will self destruct on failure normally
     }

 // save the default menu handle
     ASSERT(m_hWnd != NULL);
     m_hMenuDefault = ::GetMenu(m_hWnd);

 // load accelerator resource
     LoadAccelTable(MAKEINTRESOURCE(nIDResource));

     if (pContext == NULL)   // send initial update
          SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

     return TRUE;
}

 

可以看到在LoadFrame中主要做了2件事,第一,注册窗口。第二,创建窗口。先看AfxDeferRegisterClass()它是一个全局函数,在文件AFXIMPL.H中可以看到

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

WINCORE.CPP中可以追踪到AfxEndDeferRegisterClass(fClass)如下:

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{

 // mask off all classes that are already registered
     AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
     fToRegister &= ~pModuleState->m_fRegisteredClasses;
     if (fToRegister == 0)
          return TRUE;

     LONG fRegisteredClasses = 0;

 // common initialization
WNDCLASS wndcls;
 
memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults
 wndcls.lpfnWndProc = DefWindowProc;
 wndcls.hInstance = AfxGetInstanceHandle();
 wndcls.hCursor = afxData.hcurArrow;

 INITCOMMONCONTROLSEX init;
 init.dwSize = sizeof(init);

 // work to register classes as specified by fToRegister, populate fRegisteredClasses as //we go

     if (fToRegister & AFX_WND_REG)
     {

  // Child windows - no brush, no icon, safest default class styles
          wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
 
         wndcls.lpszClassName = _afxWnd;
          if (AfxRegisterClass(&wndcls))
          fRegisteredClasses |= AFX_WND_REG;
     }

     if (fToRegister & AFX_WNDOLECONTROL_REG)
     {

  // OLE Control windows - use parent DC for speed
          wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW |  CS_VREDRAW;

          wndcls.lpszClassName = _afxWndOleControl;
 
    if (AfxRegisterClass(&wndcls))

          fRegisteredClasses |= AFX_WNDOLECONTROL_REG;
     }

 if (fToRegister & AFX_WNDCONTROLBAR_REG)
    {

  // Control bar windows
        wndcls.style = 0;   // control bars don't handle double click
        wndcls.lpszClassName = _afxWndControlBar;
        wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

    if (AfxRegisterClass(&wndcls))

              fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;
     }

 if (fToRegister & AFX_WNDMDIFRAME_REG)
   {

  // MDI Frame window (also used for splitter window)
    wndcls.style = CS_DBLCLKS;
    wndcls.hbrBackground = NULL;//

       if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame,AFX_IDI_STD_MDIFRAME))
    fRegisteredClasses |= AFX_WNDMDIFRAME_REG;
 }

     if (fToRegister & AFX_WNDFRAMEORVIEW_REG)

 {

  // SDI Frame or MDI Child windows or views - normal colors

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

 wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

  if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))

   fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;

}

 if (fToRegister & AFX_WNDCOMMCTLS_REG)
    {

  // this flag is compatible with the old InitCommonControls() API

      init.dwICC = ICC_WIN95_CLASSES;
 
     fRegisteredClasses |= _AfxInitCommonControls(&init,           AFX_WIN95CTLS_MASK);

     fToRegister &= ~AFX_WIN95CTLS_MASK;
 }

 if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)
 {

      init.dwICC = ICC_UPDOWN_CLASS;
      fRegisteredClasses |= _AfxInitCommonControls(&init,   AFX_WNDCOMMCTL_UPDOWN_REG);
 }

 if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG)
 {

      init.dwICC = ICC_TREEVIEW_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG);
 }

 if (fToRegister & AFX_WNDCOMMCTL_TAB_REG)
 {

      init.dwICC = ICC_TAB_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TAB_REG);
 }

 if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG)
 {

      Init.dwICC = ICC_PROGRESS_CLASS;
      fRegisteredClasses |= _AfxInitCommonControls(&init,  AFX_WNDCOMMCTL_PROGRESS_REG);
 }

 if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG)
 {

      init.dwICC = ICC_LISTVIEW_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG);
 }
 if (fToRegister &
AFX_WNDCOMMCTL_HOTKEY_REG
)
 {
      init.dwICC = ICC_HOTKEY_CLASS;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG);
 }
 if (fToRegister &
AFX_WNDCOMMCTL_BAR_REG
)
 {
      init.dwICC = ICC_BAR_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG);
 }
 if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG)
 {
      init.dwICC = ICC_ANIMATE_CLASS;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ANIMATE_REG);
 }
 if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG)
 {
      init.dwICC = ICC_INTERNET_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG);
 }
 if (fToRegister & AFX_WNDCOMMCTL_COOL_REG)
 {
      init.dwICC = ICC_COOL_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG);
 }
 if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG)
 {

      init.dwICC = ICC_USEREX_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG);
 }

 if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)
 {

      init.dwICC = ICC_DATE_CLASSES;
      fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG);
 }

 // save new state of registered controls
     pModuleState->m_fRegisteredClasses |= fRegisteredClasses;

 // special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG
     if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK)
    {

         pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
         fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
    }

 // must have registered at least as mamy classes as requested
    return (fToRegister & fRegisteredClasses) == fToRegister;
}

 

至此可以看到MFC默认的注册了很多窗口类,而其中调用了AfxRegisterClass函数。而AfxRegisterClass函数实现如下:

BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
     WNDCLASS wndcls;
     if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
           &wndcls))
     {
  // class already registered
           return TRUE;
     }

     if (!::RegisterClass(lpWndClass))
    {
          TRACE1("Can't register window class named %s/n",
           lpWndClass->lpszClassName);
          return FALSE;
    }

   if (afxContextIsDLL)
   {
       AfxLockGlobals(CRIT_REGCLASSLIST);
       TRY

      {

   // class registered successfully, add to registered list
          AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
          LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList;
   // the buffer is of fixed size -- ensure that it does not overflow
          ASSERT(lstrlen(lpszUnregisterList) + 1 +
          lstrlen(lpWndClass->lpszClassName) + 1 <
          _ countof(pModuleState->m_szUnregisterList));
   // append classname + newline to m_szUnregisterList
            lstrcat(lpszUnregisterList, lpWndClass->lpszClassName);
           TCHAR szTemp[2];
           szTemp[0] = '/n';
           szTemp[1] = '/0';
           lstrcat(lpszUnregisterList, szTemp);
      }

      CATCH_ALL(e)
      {

          AfxUnlockGlobals(CRIT_REGCLASSLIST);

          THROW_LAST();
   // Note: DELETE_EXCEPTION not required.
      }

      END_CATCH_ALL
      AfxUnlockGlobals(CRIT_REGCLASSLIST);
  }

  return TRUE;
}

 

可以看到最终调用Windows API函数实现窗口类的注册。再次回到CFrameWnd::LoadFrame()函数,接下来就是产生窗口的操作了。LoadFrame中的Create调用依据多态性,应调用派生类的Create函数,由于派生类没有改写,此处调用CFrameWndCreate函数。如下(在WINFRM.CPP中):

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
  LPCTSTR lpszWindowName,DWORD dwStyle, const RECT& rect,CWnd*  pParentWnd,LPCTSTR lpszMenuName,DWORD dwExStyle, CCreateContext* pContext)

{

     HMENU hMenu = NULL;
     if (lpszMenuName != NULL)
    {

  // load in a menu that will get destroyed when window gets destroyed
         HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);

         if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

        {

            TRACE0("Warning: failed to load menu for CFrameWnd./n");
            PostNcDestroy();            // perhaps delete the C++ object
            return FALSE;
        }

 }

    m_strTitle = lpszWindowName;    // save title for later

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

  pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

{

TRACE0("Warning: failed to create CFrameWnd./n");

  if (hMenu != NULL)

        DestroyMenu(hMenu);

  return FALSE;

}

 return TRUE;
}

后者又调用了CreateEx函数,CWndCreateEx函数,而CFrameWnd函数并没有改写它,故调用CWnd类的CreateEx函数,在WINCORE.cpp中实现如下:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

     LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

 // allow modification of several common create parameters

     CREATESTRUCT cs;
     cs.dwExStyle = dwExStyle;
     cs.lpszClass = lpszClassName;
     cs.lpszName = lpszWindowName;
     cs.style = dwStyle;
     cs.x = x;
     cs.y = y;
     cs.cx = nWidth;
     cs.cy = nHeight;
     cs.hwndParent = hWndParent;
     cs.hMenu = nIDorHMenu;
     cs.hInstance = AfxGetInstanceHandle();
     cs.lpCreateParams = lpParam;

     if (!PreCreateWindow(cs))
     {
          PostNcDestroy();
          return FALSE;
     }

     AfxHookWindowCreate(this);
     HWND hWnd =
::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
     cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu,  cs.hInstance, cs.lpCreateParams);//Windows API
完成窗口类的一些额外风格设置

#ifdef _DEBUG
    if (hWnd == NULL)
    {

    TRACE1("Warning: Window creation failed: GetLastError returns0x%8.8X/n",   GetLastError());

}

#endif

    if (!AfxUnhookWindowCreate())
     PostNcDestroy();        // cleanup if CreateWindowEx fails too soon

     if (hWnd == NULL)
     return FALSE;
     ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
     return TRUE;
}

 

该函数先是调用PreCreateWindow函数,依据多态性,先调用派生类,接着是CMDIFrameWnd,然后是CFrameWndPreCreateWindow函数

WINFRM.CPP中如下:

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{

     if (cs.lpszClass == NULL)
 {

  VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
  cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
 }

 if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
  cs.style |= FWS_PREFIXTITLE;

 if (afxData.bWin4)

  cs.dwExStyle |= WS_EX_CLIENTEDGE;

 return TRUE;

}

沿着AfxDeferRegisterClass追踪下去,和上面的相同,都为MFC注册窗口类。

追踪完毕,回到开始的InitInstance函数中,接下来就是ShowWindowUpdateWindow了。UpdateWindow会发出WM_PAINT消息。再回到AfxWinMain()函数就是调用pApp->Run()函数了。因为派生类没有改写所以调用CWinApp::Run()函数,在APPCORE.CPP中实现如下:

int CWinApp::Run()
{

     if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
     {

  // Not launched /Embedding or /Automation, but has no main window!

     TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting     application./n");
      AfxPostQuitMessage(0);

     }

    return CWinThread::Run();
}

 

CWinThread::Run实现如下,在文件THRDCORE.CPP中:

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
}

 

 

CWinThread::PumpMessage实现如下:

BOOL CWinThread::PumpMessage()
{
     ASSERT_VALID(this);

     if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
     {
         #ifdef _DEBUG
          if (afxTraceFlags & traceAppMsg)
          TRACE0("CWinThread::PumpMessage - Received WM_QUIT./n");
          m_nDisablePumpCount++; // application must die
   // Note: prevents calling message loop things in 'ExitInstance'
   // will never be decremented
         #endif

          return FALSE;
     }

#ifdef _DEBUG
     if (m_nDisablePumpCount != 0)
     {

      TRACE0("Error: CWinThread::PumpMessage called when not permitted./n");

  ASSERT(FALSE);

 }

#endif

#ifdef _DEBUG
 if (afxTraceFlags & traceAppMsg)

      _AfxTraceMsg(_T("PumpMessage"), &m_msgCur);

#endif

 // process this message

if (m_msgCur.message != WM_KICKIDLE&& !PreTranslateMessage(&m_msgCur))

 {

      ::TranslateMessage(&m_msgCur);
          ::DispatchMessage(&m_msgCur);
     }

 return TRUE;
}

可以看到都是调用底层Windows API实现。程序退出时回到AfxWinInit最后调用AfxWinTerm终止程序。而消息映射的实现是利用钩子函数在AfxWndProc中实现的,最后没有处理的消息都用DefWindowProc函数处理