深入剖析MFC基础框架——跟踪MFC单文档程序的执行过程:

来源:互联网 发布:智能停车场收费软件 编辑:程序博客网 时间:2024/05/20 14:26


跟踪MFC单文档程序的执行过程:


1、CTestApp theApp; //表示应用程序本身,全局对象

2、CTestApp::CTestApp(){ }  //调用构造函数  < class CTestApp::public CWinApp >

// CWinApp在APPCORE文件中,class CWinApp::public CWinThread

以下提到的文件在   D:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC 下。

3、//在APPMODUL中定义

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)// 主函数

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

4、// 在WINMAIN.cpp中定义

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

......

if (!pThread->InitInstance()){//虚函数,调用子类的InitInstance()函数。pThread为指向CWinThread对象的指针

......

}

nReturnCode = pThread->Run(); //完成消息循环

}

5、BOOL CTestApp::InitInstance()  // 子类的函数

{

......

}

6、// 在WINCORE.cpp中定义

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)  //MFC中提前定义了几个窗口类,在此决定注册哪一个
{

.......

if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WND_REG;

// 有n个if语句

} // 单文档牵扯到文档管理,所以注册窗口类位置提前了,多文档没有

7、BOOLCMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
//  the CREATESTRUCT cs


return TRUE;
}

8、// CFrameWnd::PreCreateWindow在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 在AFXIMPL中定义,是一个宏:

// #define AfxDeferRegisterClass(fClass)    AfxEndDeferRegisterClass(fClass) 
9、因此此处执行的是 步骤6

10、创建窗口:// WINFRM中定义:

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

.......

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,   // CreateEx是基类(CWnd)中的函数
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)){

......

}  

} //CFrameWnd::LoadFrame()会调用此函数,此处就不演示代码了

11、在WINCORE中定义:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */)
{
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}

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))//又调用一次,这是虚函数,调用的是子类(CMainFrame)中的,若有的话。
{
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);

......

return TRUE;
}

12、执行 步骤7

13、执行 步骤8:

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs);

// cs成员变量和CreateWindowEx中参数相同,次序相反。目的:产生窗口之前有机会去修改窗口外观。

// 后面再循环执行后面这几步几次,检查....

14、窗口显示更新:

CWinApp有一个成员变量指针—m_PMainWnd,指向框架类CMainFrame对象。当通过  BOOL CTestApp::InitInstance()内的 ProcessShellCommand(cmdInfo)调用时,框架已经创建完成,尔后调用:

m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

完成窗口的显示更新(打断点时会发现窗口显示为透明)。

15、消息循环//在THRDCORD.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
}

BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
{

......

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
}
return TRUE;
}

//以上为消息映射(实际上调用了Win32的函数)



0 0