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的定义窗口是不同的。

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