MFC程序的誕生過程

第6章 MFC程序的生死因果的一個分析

以下是對第6章 MFC程序的生死因果的一個分析

大致過程如下:

1  產生一個全局變量CMyWinApp對象theApp,在hello.cpp中。

2  進入AfxWinMain

3  AfxWinMain首先調用AfxWinInit()【此函數用於AFX內部初始化工作】

4  AfxWinMain繼續調用CWinApp::InitApplicatio()【此函數負責一些內存的工作】

5  AfxWinMain繼續調用CMyWinApp::InitInstance()【爲啥是CMyWinApp,因爲需函數,this指針指向了CMyWinApp

    注意,這個函數一般都得重載,自己寫

6 CMyWinApp::InitInstance()中先new了一個CMyFrameWnd,作爲主窗口,而new的這個過程調用了窗口的構造函數。

主窗口的構造函數需要重載。

下面爲hello程序中的構造函數

CMyFrameWnd::CMyFrameWnd()
{
   Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault,
          NULL, "MainMenu");     // "MainMenu" ﹚竡 RC 
}

8  構造函數調用Create,註冊並創建窗口類【1

9  調用CWinApp::Run激活消息循環【2

以上便是hello這個程序的誕生過程。


/*************************華麗麗的分割線************************/

再解釋一下【1】與【2

1

1  Create函數有六個參數,意義書上有寫。我們來看一下定義在WINFRM.cpp中的Create函數定義

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這個函數;

BOOL CFrameWnd::Create(。。。){...CreateEx()...};

2  CreateEx()中調用了PreCreateWindow();3

3  PreCreateWindow函數定義如下

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 if (cs.lpszClass == NULL)//如果Create第二個參數爲NULL他會制定爲什麼【3
 {
  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;
}
4  AfxDeferRegisterClass是一個宏 他的意義就在於調用AfxEndDeferRegisterClass
5  AfxEndDeferRegisterClass就是對不同的窗口類進行不同的操作。

6  截取了一段AfxEndDeferRegisterClass,當然我們可以在這個函數裏增加if自定義窗口類
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

{

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

}

 }

2

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();

}

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())// 收到WM_QUIT消息

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

}

PeekMessage的工作即是獲取消息分發派送消息,如果沒有消息則返回false

3】不同窗口中PreCreateWindow()的對於null的定義窗口是不同的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章