第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的这个过程调用了窗口的构造函数。
7 主窗口的构造函数需要重载。
下面为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的定义窗口是不同的。