MFC启动过程

一个MFC程序的运行过程

http://www.sunhongfeng.com/2010/01/how_mfc_run/

1.由于theApp是全局对象,因此会在进入WinMain()之前完成构造,theApp的构造动作会导致一系列的对theApp的初始化动作:
pModuleState->m_pCurrentWinApp = this;

2.接着进入WinMain(),WinMain()(_tWinMain(),这是为了UniCode而准备的一个宏)直接调用AfxWinMain(),AfxWinMain()发挥真正应该由WinMain()发挥的作用,它取得theApp,然后必须先调用AfxWinInit(),再用取得的指向theApp的指针pApp调用InitApplication()、InitInstance()和Run(),最后调用AfxWinTerm()终止程序。
即AfxWinMain()中的动作相当于:

AfxWinInit();
CWinApp::InitApplication();
CMyWinApp::InitInstance();
CWinApp::Run();

3.AfxWinInit()做什么?
首先将WinMain()传进来的四个参数保留在theApp的成员变量里。
调用AfxInitThread(),此函数又调用::SetWindowHookEx(),不知干啥。另外此函数还将消息队列尽量加大到96。

4.CWinApp::InitApplication()做什么?
会做一些与CDocManager()和Document Template相关的工作,是MFC的内部管理范畴。

5.CMyWinApp::InitInstance()做什么?
终于来到了我们可以改写的InitInstance(),这个函数是CWinApp的虚函数,CMyWinApp通常要改写它,其实在CWinApp中InitInstance()是一个空函数。
InitInstance()的动作如下:

m_pMainWnd = new CMyFrameWnd();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();

InitInstance()首先会创建一个CMyFrameWnd对象,并将指针保留在m_pMainWnd中。这个CMyFrameWnd对象的创建过程就会导致主窗口的登记和建立,因为CFrameWnd的构造函数中会调用Create()函数,而这个函数负责创建窗口(通过调用CreateWindowEx),窗口风格使用最常见的WS_OVERLAPPEDWINDOW。但是这仅仅是创建窗口,窗口类注册的动作(必须先于窗口的创建)又发生在哪里呢?其实Create()的调用会导致CWnd::CreateEx()的调用,此函数才是真正调用CreateWindowEx()创建窗口者,在调用CreateWindowEx()之前会调用CFrameWnd::PreCreateWindow(),此函数判断传入的窗口类名lpszClassName是否为NULL,若是则通过一系列的调用(非常之绕)为其注册默认窗口类别。由于每个窗口创建过程中PreCreateWindow()都只在创建之前被调用,因此窗口的注册大多在创建之前发生。CWnd及其派生类的各个不同PreCreateWindow()函数为不同窗口指定了不同的默认窗口类别:
CWnd使用的窗口类别是_afxWnd
CFrameWnd和CMDIChildWnd使用的窗口类别是_afxWndFrameOrView
CMDIFrameWnd使用的窗口类别是_afxWndMDIFrame
综上,InitInstance()中的第一个动作――创建CMyFrameWnd对象――完成了窗口的创建。之后的动作就很直观了,ShowWindow()显示窗口,UpdateWindow()发送WM_PAINT消息更新窗口。

6.回到AfxWinMain()中,接下来执行的是CWinApp::Run()。Run()所做的正是维持程序运行的“消息循环”。CWinApp::Run()会调用CWinThread::Run(),此Run()中有消息循环,通过PumpMessage()得到并转发消息(调用::GetMessage()、::TranslateMessage()、::DispatchMessage(),一如SDK!)。但是转发到哪里呢?窗口函数呢?原来在MFC为我们注册默认窗口类的时候已经指定了窗口函数为DefWindowProc(),但是真正处理消息的又不是它,而是一个全局函数AfxWndProc(),这是MFC通过hook和subclassing技术做到的,暂且不提。

综上,MFC为我们的程序提供了WinMain()、注册了窗口类、创建了窗口甚至提供了窗口函数,留给我们做的只是写出响应消息的处理函数,而这些消息和处理函数如何对应起来还要靠MFC六大关键技术之一的Message Mapping(消息映射)。消息映射机制的目的是首先搭建起消息和消息处理函数对应的大框架,再通过宏的机制让程序员能够方便地添加消息和消息处理函数之间的对应关系。

7.在程序运行的过程中,程序不断地由消息所驱动,直到用户动作发出了WM_CLOSE消息,程序即将关闭,过程是:由于CMyFrameWnd没有设立WM_CLOSE的处理函数,因此该消息被送往预设处理函数,预设函数对WM_CLOSE的处理是调用::DestroyWindow(),进而发送WM_DESTROY消息,WM_DESTROY消息同样会被送到预设处理函数,预设函数对WM_DESTROY的处理方法是调用::PostQuitMessage(),发送WM_QUIT,CWinApp::Run()在收到WM_QUIT后会结束自己的消息循环,并调用ExitInstance(),这是CWinApp的虚函数,可被CMyWinApp改写,调用过此函数后,回到AfxWinMain()中调用AfxWinTerm()结束程序。

对应 GUI lite

<创建的是MFC 基于对话框项目>
1, CHelloStarApp theApp;
全局对象的定义和构造,
其中 class CHelloStarApp : public CWinApp 这里有个继承关系

virtual BOOL **InitInstance**(); // CWinApp的虚函数
BOOL CHelloStarApp::**InitInstance**() // 对虚函数重新实现,多态,动态绑定,覆盖

2,重点就在这里的 CHelloStarApp::InitInstance()
在这个函数中做了很多工作,看着应该是包括注册创建窗口等,MFC为创建第一个对话框做准备

最终会执行 创建/定义 一个对象( 这里应该是MFC创建的第一个对话框)
CHelloStarDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();

注意:构造函数,拷贝构造函数和析构函数,不能被派生类继承,可以被调用(传实参),下面是调用的格式
CHelloStarDlg::CHelloStarDlg(CWnd* pParent /=nullptr/) : CDialogEx(IDD_HelloStar_DIALOG, pParent)

下面是非常重要的:

  • a) INT_PTR nResponse = dlg.DoModal(); // DoModal()方法 应该是MFC对话框类的一个方法,开始执行创建对话框

  • b) 执行完 DoModal()后开始执行下面的语句 “进行消息映射”

    BEGIN_MESSAGE_MAP(CHelloStarDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_ERASEBKGND()
    END_MESSAGE_MAP()

  • c) 最终执行下面的语句 OnInitDialog() 开始了创建初始对话框的消息处理函数中,

    // CHelloStarDlg message handlers
    BOOL CHelloStarDlg::OnInitDialog()
    ------- 在这里插入代码片// TODO: Add extra initialization here (这里就是MFC留给我们的接口,然后可以在MFC基于对话框的接口上开始自己的代码了)
    ------- AfxBeginThread(CHelloStarDlg::ThreadHelloStar, NULL); // 创建一个我们自己的线程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值