您的位置:首页 > 其它

MFC启动过程&单文档MFC程序的启动详细过程

2012-12-29 19:29 465 查看

MFC启动过程

1. 首先说一下MFC程序的启动过程.

每个MFC程序都有一个全局的应用程序类的对象, 在面向对象程度非常好的MFC程序中, 应该只有这一个全局的对象.

MFC应用程序启动时, 首先创建这个应用程序对象, 比如对象名为theApp, 这时将调用这个对象的构造函数来初始化theApp.然后由应用程序框架调用MFC提供的AfxWinMain主函数. 在这个主函数中, 首先获得应用程序对象theApp的指针, 然后通过这个指针调用程序程序对象的有关函数, 来完成程序的初始化和启动工作, 最后调用Run函数, 进入消息循环. 主要代码如下:

CTheApp theApp;

BOOL CTheApp::InitInstance()

{

....

m_pMainWnd = new CTheWindow();//调用窗口类的构造函数来创建一个窗口

m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口

m_pMainWnd->UpdateWindow();//更新窗口上的元素

return TRUE;

}

//////////////

int AFXAPI AfxWinMain()

{

CWinThread *pThread = AfxGetThread();//获取主线程指针

CWinApp *pApp = AfxGetApp();

AfxWinInit();

....

pApp->InitApplication();

...

pThread->InitInstance();//初始化应用程序实例

...

nReturnCode = pThread->Run();//开始消息循环

}


与普通的WIN32 SDK应用程序相比, 入口函数换成AfxWinMain, 初始化和启动工作主要交给应用程序类处理. 另外, 创建管理窗口由窗口类负责, 创建创建一个窗口只需要几行便可实现, 完全不用像WIN32 SDK那样用大量代码去注册窗口类, 而且由于消息映像机制的引进, 不用再去写麻烦的回调函数和SWITCH-CASE语句. 当然, MFC的强大远远不只这些, 比如能够方便的实现文档/视图结构和序列化就是它最强大的一个功能之一.

另外, 在AfxWinMain中可以看到, 运行代码和消息循环果然是由主线程来完成的. 此外, 可以看到主线程完成了界面管理(如窗口创建)和消息循环(Run), 这与线程的使用中所给的指导原则完全一致.

2. 再看一个最简单的MFC程序的代码. 这个程序包含一个.H文件和一个.CPP文件, 代码如下:

//HELLO.H:

class CTheApp : public CwinApp//应用程序类定义

{

public:

virtual BOOL InitInstance ();

};

class CMainWindow : public CframeWnd//主窗口类定义

{

public:

CMainWindow ();

protected:

afx_msg void OnPaint ();

DECLARE_MESSAGE_MAP ()

};

//HELLO.CPP

#include <afxwin.h>

#include "Hello.h"

CTheApp theApp;//全局应用程序对象

/////////////////////////////////////////////////////////////////////////

// CMyApp member functions

BOOL CTheApp::InitInstance ()//初始化应用应用程序实例: 创建并显示一个窗口

{

m_pMainWnd = new CMainWindow;

m_pMainWnd->ShowWindow (SW_SHOW);

m_pMainWnd->UpdateWindow ();

return TRUE;

}

/////////////////////////////////////////////////////////////////////////

// CMainWindow message map and member functions

BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)//消息映射

ON_WM_PAINT ()

END_MESSAGE_MAP ()

CMainWindow::CMainWindow ()//构造一个窗口

{

Create (NULL, _T ("Hello MFC!"));

}

void CMainWindow::OnPaint ()//重绘窗口内容

{

CPaintDC dc (this);

CRect rect;

GetClientRect (&rect);

dc.DrawText (_T ("Hello, MFC"), -1, &rect,

DT_SINGLELINE | DT_CENTER | DT_VCENTER);

}


在上面的代码中可以看到一个最简单的MFC应用程序的组成和结构:

首先, 应该声明一个应用程序类来负责程序的初始化和启动, 并且需要一个全局的应用程序类的对象, 它将被AfxWinMain使用来初始化应用程序. 此外, 应用程序类的InitInstance虚函数是必须要重载的函数, 要在其中放置实际的初始化代码, 比如载入一些程序设置选项, 创建一个窗口等.

第二, 应该声明一个主窗口类负责创建和管理主窗口及主窗口中的元素. 实际创建主窗口的代码应该在主窗口的构造函数中完成. 至于创建主窗口中的子窗口如菜单, 按钮等, MFC专门编写了一个虚函数OnCreate来负责.

第三, 要有消息映射机制来实现消息循环. 这部分代码的样子如上所示. 当然, 要响应一个消息, 必须有对应的消息函数. 比如上面所演示的, 用OnPaint来响应WM_PAINT消息, 当WM_PAINT消息发出时, 就调用OnPaint. 跟WIN32 SDK程序中每个窗口都有自己独立的消息循环一样, 每个窗口都有自己单独的消息映射.

在WIN32 SDK中要创建类似的程序, 所需要写的代码量比上面所演示的要多的多, 而且结构没有上面的代码那样清晰. 从第一个小程序开始, MFC的强大功能已经有所体现. 由于采用了面向对象的思想, 即使在一些大规模的程序中, MFC程序仍然能够保持清晰的组织结构, 并且代码重用将体现的更加强大. “MFC应该是开发WINDOWS平台桌面应用程序的首选工具”------有位大牛曾经这么说过.

我做了格式上的修改,原址:/article/11391991.html

单文档MFC程序的启动详细过程

1、定义和构造全局应用程序对象,CSDITestApp theApp;

//这个对象用来唯一标示应用程序,相当于SDK中的应用程序句柄hInstance

1.1 定义theApp,为其分配内存空间,由系统自动完成

1.2 调用构造函数:CSDITestApp:: CSDITestApp();

1.2.1 调用基类构造函数:CWinApp:: CWinApp(NULL);

pThreadState->m_pCurrentWinThread = this;

pModuleState->m_pCurrentWinApp = this; //AfxGetApp()返回的就是这个值,代表了theApp

m_pDocManager = NULL;

//其他都设为NULL或0,因为此时WinMain还没有启动

1.2.2 子类构造函数CSDITestApp:: CSDITestApp();什么都没做

2、调用WinMain函数:这是编译链接的时候从外部链接进来的,确切的函数为tWinMain(AfxWinMain)

2.1 调用AfxWinMain函数

2.1.0 首先获取CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); //这是在1.2.1中设置的指针

2.1.1 调用AfxWinInit(); //设置四个入口参数

2.1.2 调用CWinApp::InitApplication(); //虚函数,子类可以重载,但一般不重载

//设置成员对象CWinApp::m_pDocManager的静态变量CDocManager::bStaticInit为FALSE

2.1.3 调用CSDITestApp::InitInstance(); //虚函数,子类已重载,一定要重载

2.1.3.1 定义构造CSingleDocTemplate对象

2.1.3.1.1 调用基类构造函数CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)

//设置 m_nIDResource = nIDResource;

// m_pDocClass = pDocClass;

// m_pFrameClass = pFrameClass;

// m_pViewClass = pViewClass;

//调用 CDocTemplate::LoadTemplate(); 用m_nIDResource设置m_strDocStrings

2.1.3.1.2 m_pOnlyDoc = NULL;

2.1.3.2 调用CWinApp::AddDocTemplate(pDocTemplate)

2.1.3.2.1 调用CDocManager::AddDocTemplate(pDocTemplate)//将pDocTemplate加入到CDocManager::m_templateList中

2.1.3.3 定义构造CCommandLineInfo cmdInfo

2.1.3.3.1 调用CCommandLineInfo:: CCommandLineInfo();//设置m_nShellCommand = FileNew

2.1.3.4 调用CWinApp::ParseCommandLine(); //分析命令行,详细过程忽略

2.1.3.5 调用CWinApp::ProcessShellCommand(cmdInfo)

//由于m_nShellCommand = FileNew,所以这里将调用CWinApp::OnFileNew,后面细讲

//如果在MDI程序下,可设置m_nShellCommand = FileNothing,则什么都不做。因为在MDI程序下,之前已经通过LoadFrame函数创建了主窗口(MainFrame)。本文仅针对SDI程序。

2.1.3.6 调用CWnd::ShowWindow(SW_SHOW) //非虚函数,不能重载

//将调用API函数::ShowWindow显示主窗口

2.1.3.7 调用CWnd::UpdateWindow() //非虚函数,不能重载

//将调用API函数::UpdateWindow更新主窗口

2.1.4 调用CWinApp::Run(); //建立消息循环。虚函数,可以重载,一般不重载

2.1.4.1 调用CWinThread::Run()

2.1.4.1.1 调用CWinThread::PumpMessage()

2.1.4.1.1.1 调用::GetMessage(), ::TranslateMessage(), ::DispatchMessage()

2.1.4.1.1.2 如果收到WM_QUIT消息,则调用ExitInstance(),返回wParam,退出程序。

2.1.4.1.2 调用::PeekMessage(…, PM_NOREMOVE)作循环

2.1.5 调用AfxWinTerm函数,完成注销等操作

2.1.6 退出程序

3、调用CWinApp::OnFileNew()的过程 //虚函数,可重载

//该过程要构造Document, FrameWnd和View类对象,并创建MainFrame和View窗口。实际上OnFileNew函数并不是直接调用的,而是通过CCmdTarget::OnCmdMsg发送一个ID_FILE_NEW来调用的

3.1 调用CDocManager::OnFileNew()函数

3.1.1 获取CDocTemplate* pTemplate对象指针 //在2.1.3.2.1中加入的,如果是MDI程序,会调出对话框,询问使用哪一个DocTemplate

3.1.2 调用CSingleDocTemplate::OpenDocumentFile(NULL);//虚函数,CDocTemplate基类中为纯虚函数,所以调用子类的函数

3.1.2.1 调用CDocTemplate::CreateNewDocument();

3.1.2.1.1 调用CRuntimeClass::CreateObject()创建并构造一个CSDITestDoc的对象 //CRuntimeClass的含义请看《深入浅出MFC》

3.1.2.1.2 调用CSingleDocTemplate::AddDocument()

3.1.2.1.2.1 调用基类CDocTemplate::AddDocument(),将CSDITestDoc对象的成员m_pDocTemplate设为当前模板this指针。

3.1.2.1.2.2 设置CSingleDocTemplate::m_pOnlyDoc = pDocument; //单文档只能有一个

3.1.2.2 调用CDocTemplate::CreateNewFrame(pDocument, NULL)

3.1.2.2.1调用CRunTimeClass::CreateObject()创建并构造一个CMainFrame的对象

3.1.2.2.2 调用CFrameWnd::LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, …) //该函数将完成注册窗口类结构wndclass,创建主窗口,创建view窗口,创建工具条状态条等任务,后面细讲

3.1.2.3 调用CSDITestDoc::OnNewDocument() //虚函数,子类已重载,加入一些初始化代码

3.1.2.4 调用CDocTemplate::InitialUpdateFrame()

3.1.2.4.1 调用CFrameWnd::InitialUpdateFrame()

3.1.2.4.1.1 设置ActiveView //SetActiveView

3.1.2.4.1.2 SendMessageToDescendants(WM_INITIALUPDATE,…)

3.1.2.4.1.3 pView->OnActiveFrame(WA_INACTIVE, this)

3.1.2.4.1.4 ActivateFrame()

3.1.2.4.1.5 pDoc->UpdateFrameCounts

3.1.2.4.1.6 OnUpdateFrameTitle(TRUE)

4. 调用CFrameWnd::LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, …)的过程 //虚函数,可重载

4.1 调用AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG),即AfxEndDeferRegisterClass构造窗口类,并注册

4.1.1 设置wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

4.1.2 调用_AfxRegisterWithIcon注册窗口类

4.1.2.1 调用AfxRegisterClass()

//如果窗口类没有注册,则调用API函数::RegisterClass()注册窗口类 //第一次注册

4.2 调用GetIconWndClass()函数

4.2.1 调用CMainFrame::PreCreateWindow(cs) //虚函数,子类已经重载

4.2.1.1 又会调用AfxEndDeferRegisterClass注册窗口类,但此时的窗口类已经在4.1.2.1注册了,所以PreCreateWindow函数的主要功能是更新cs结构。

4.2.2 调用AfxRegisterWndClass注册窗口类 //第二次注册

4.3 调用CFrameWnd::Create()

4.3.1 调用CWnd::CreateEx

4.3.1.1 构造cs

4.3.1.2 再次调用PreCreateWindow(cs) //同样也不会注册窗口类,只是修改cs

4.3.1.3 调用API函数::CreateWindowEx创建主窗口,同时发送WM_CREATE消息

4.3.1.3.1 调用CMainFrame::OnCreate()函数响应消息 //虚函数,子类已经重载。后面详细讲述

5. 调用CMainFrame::OnCreate()函数

5.1 调用基类CFrameWnd::OnCreate()函数

5.1.1 调用CFrameWnd::OnCreateHelper函数

5.1.1.1 调用CWnd::OnCreate()函数 //调用缺省的窗口过程函数,详细过程略

5.1.1.2 调用CFrameWnd::OnCreateClient函数

5.1.1.2.1 调用CFrameWnd::CreateView函数

5.1.1.2.1.1 调用CRunTimeClass::CreateObject()创建CSDITestView类对象

//调用CView::CView()构造函数 m_pDocument = NULL;

5.1.1.2.1.2 调用CView::Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext)

// AFX_WS_DEFAULT_VIEW =WS_CHILD | WS_VISIBLE | WS_BORDER

5.1.1.2.1.2.1 调用CWnd::Create() //此函数只能创建WS_CHILD的窗口,如果是POPUP,需要用CreateEx函数

5.1.1.2.1.2.1.1 调用CWnd::CreateEx() //与4.3.1类似

//在CView::OnCreate函数中,有一个CSDITestDoc::AddView(this),该函数一方面将pView加入到CDocument的成员m_viewList中,另一方面将pView的m_pDocument指向pDocument

5.1.1.3 调用RecalcLayout函数5.2 调用CToolBar和CStatusBar创建工具条和状态条 //省略

我做了格式更改,原址:http://blogguan.blog.sohu.com/67507744.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐