• MFC学习-第2,3课 MFC框架的运行机制


    转自:http://blog.163.com/zhigang0633@126/blog/static/38790491200822711526168/

    讲述MFC AppWizard的原理与MFC程序框架的剖析。AppWizard是一个源代码生成工具,是计算机辅助程序设计工具,WinMain在MFC程序中是如何从源程序中被隐藏的,theApp全局变量是如何被分配的,MFC框架中的几个类的作用与相互关系,MFC框架窗口是如何产生和销毁的,对窗口类的PreCreateWindow和OnCreate两个函数的着重分析,Windows窗口与C++中的CWnd类的关系。

    1. 寻找WinMain入口:
    在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。路径:Microsoft Visual Studio 10.0|VC|MFC|SRC|APPMODUL.CPP:
    WinMain在APPMODUL.CPP中实现:

    _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPTSTR lpCmdLine, int nCmdShow)
    {
    // call shared/exported WinMain
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
    }
    //注意:(#define _tWinMain WinMain)

    2. 对于全局对象或全局变量来说,在程序运行即WinMain函数加载的时候,已经为全局对象或全局变量分配了内存和赋初值。
    所以:执行顺序为CTestApp theApp;(全局对象)->CTestApp ::CTestApp(){}(构造函数)->_tWinMain(){}(入口)
    说明:每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所实例化的对象,表示应用程序本身。在WIN32程序当中,表示应用程序是通过WinMain入口函数来表示的(通过一个应用程序的一个实例号这一个标识来表示的)。在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。

    3. 通过构造应用程序对象过程中调用基类CWinApp的构造函数,在CWinApp的构造函数中对程序包括运行时一些初始化工作完成了。

    CWinApp类在APPCORE.CPP中实现:
    CWinApp::CWinApp(LPCTSTR lpszAppName){...}//带参数,而CTestApp构造函数没有显式向父类传参,难道CWinApp()有默认参数?见下:
    //(在CWinApp类定义中, CWinApp(LPCTSTR lpszAppName = NULL); ) //注意:CWinApp()函数中: pThreadState->m_pCurrentWinThread = this; pModuleState->m_pCurrentWinApp = this //(this指向的是派生类CTestApp对象,即theApp)

    对于this指针到底是属于基类的还是派生类的呢,在网站上搜索了一下:

    参考:http://zhidao.baidu.com/link?url=qzkLuUebZqrSDHzNxG3e7ijc3P-RKCvH26dJtph60GL7GkrYI47ZNG4_YKtVnETCZW8Bi0YItpTw1oK-rMMrtq

    运行顺序:CWinApp::CWinApp();->CTestApp theApp;->CTestApp ::CTestApp();->CWinApp::CWinApp();->CTestApp ::CTestApp();->_tWinMain(){}

    4. _tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,在每个类中都能被调用。应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。
    AfxWinMain()函数在WINMAIN.CPP中:
    在AfxWinMain()函数中:

    int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        _In_ LPTSTR lpCmdLine, int nCmdShow)
    {
        ASSERT(hPrevInstance == NULL);
    
        int nReturnCode = -1;
        CWinThread* pThread = AfxGetThread();
        // 说明:pApp存储的是指向WinApp派生类对象(theApp)的指针。
    // AfxGetApp()函数的定义
    // _AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
    // { return afxCurrentWinApp; }
    // #define afxCurrentWinApp AfxModuleState->m_pCurrentWinApp
    CWinApp* pApp = AfxGetApp();
        // AFX internal initialization
        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
            goto InitFailure;
    
        // App global initializations (rare)
        if (pApp != NULL && !pApp->InitApplication()) //MFC类的一些内部初始化管理。
            goto InitFailure;
    
        // Perform specific initializations
        /*说明:pThread也指向theApp,由于基类中virtual BOOL InitInstance()定义为虚函数,所以调用pThread->InitInstance()的时候,调用的是派生类CTestApp      的InitInstance()函数.*/
        if (!pThread->InitInstance()) 
        {
           ....
        }
        nReturnCode = pThread->Run();  //说明:pThread->Run()完成了消息循环。
    
    ...
    }

    5. 注册窗口类:AfxEndDeferRegisterClass();

    //AfxEndDeferRegisterClass()在WINCORE.CPP中实现:
    BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){...}
    //说明:设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。

    运行顺序:CWinApp::CWinApp();->CTestApp theApp;->CTestApp ::CTestApp();->CWinApp::CWinApp();->CTestApp::CTestApp();->_tWinMain(){}//进入程序
    ->AfxWinMain();->pApp->InitApplication();->pThread->InitInstance()//父类InitInstance虚函数;
    ->CTestApp::InitInstance()//子类实现函数;
    ->AfxEndDeferRegisterClass(LONG fToRegister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在PreCreateWindow中进行注册)//之后进入创建窗口阶段

    6. CMainFrame的PreCreateWindow()://主要是注册窗口类,以及在创建窗口之前让用户有机会对style进行修改

    BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
    {
    if( !CFrameWnd::PreCreateWindow(cs) )
    return FALSE;
    return TRUE;
    }
    //说明:
    //CFrameWnd::PreCreateWindow()函数所在文件:WINFRM.CPP

    BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT
    & cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); //判断AFX_WNDFRAMEORVIEW_REG型号窗口类是否注册,如果没有注册则注册 cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background //把注册后的窗口类名赋给cs.lpszClass } if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4) cs.style |= FWS_PREFIXTITLE; if (afxData.bWin4) cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; } // 其中: // virtual BOOL PreCreateWindow(CREATESTRUCT& cs);//PreCreateWindow()是个虚函数,如果子类有,则调用子类的。 // #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) // const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;//WINCORE.CPP文件中,定义为全局数组。 //#define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView")

    7. 创建窗口:

    这里只讲解了框架窗口的创建,它的Create()函数在WINFRM.CPP中:

    CFrameWnd::Create(...){
    ...
    CreateEx(...);//从父类继承来的,调用CWnd::CreateEx().
    ...
    }
    CWnd::CreateEx() //函数在WINCORE.CPP中:
    BOOL CWnd::CreateEx(...){
    ...
    if (!PreCreateWindow(cs))//虚函数,如果子类有调用子类的。
    {
    PostNcDestroy();
    return FALSE;
    }
    ...
    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);
    ...
    }

    说明:CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前可以通过PreCreateWindow(cs)修改cs结构体成员来修改所要的窗口外观。PreCreateWindow(cs))//是虚函数,如果子类有调用子类的。

    HWND CreateWindowEx(
    DWORD dwExStyle, 
    LPCTSTR lpClassName, 
    LPCTSTR lpWindowName, 
    DWORD dwStyle, 
    int x, 
    int y, 
    int nWidth, 
    int nHeight, 
    HWND hWndParent, 
    HMENU hMenu, 
    HINSTANCE hInstance, 
    LPVOID lpParam 
    )
    typedef struct tagCREATESTRUCT { // cs 
    LPVOID lpCreateParams; 
    HINSTANCE hInstance; 
    HMENU hMenu; 
    HWND hwndParent; 
    int cy; 
    int cx; 
    int y; 
    int x; 
    LONG style; //窗口的类型
    LPCTSTR lpszName; //窗口的名字
    LPCTSTR lpszClass; //类名
    DWORD dwExStyle; //扩展的对象
    } CREATESTRUCT; //结构体

    8. 显示和更新窗口:

    // CTestApp类,TestApp.cpp中
    m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口,m_pMainWnd指向框架窗口
    m_pMainWnd->UpdateWindow();//更新窗口
    // 说明:
    class CTestApp : public CWinApp{...}
    class CWinApp : public CWinThread{...}
    class CWinThread : public CCmdTarget
    {
    ...
    public:
    CWnd* m_pMainWnd;
    ...
    }

    9. 消息循环:

    int AFXAPI AfxWinMain()
    { ...
    // Perform specific initializations
    if (!pThread->InitInstance()){...}
    //完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
    nReturnCode = pThread->Run();
    //继承基类Run()方法,调用CWinThread::Run()来完成消息循环
    ...
    }
    //CWinThread::Run()函数在THRDCORE.CPP中
    int CWinThread::Run()
    { ...
    // phase2: pump messages while available
    do//消息循环
    {
    // pump message, but quit on WM_QUIT
    if (!PumpMessage())//取消息并处理
    return ExitInstance();
    ...
    } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
    ...
    }

    说明:
    BOOL PeekMessage(,,,,)函数说明
    The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure.
    If a message is available, the return value is nonzero.
    If no messages are available, the return value is zero.

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

    BOOL CWinThread::PumpMessage()
    {
    ...
    if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))//取消息
    {...}
    ...
    // process this message
    if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
    {
    ::TranslateMessage(&m_msgCur);//进行消息(如键盘消息)转换
    ::DispatchMessage(&m_msgCur);//将消息路由给操作系统,由相应的消息响应函数来处理
    }
    return TRUE;
    }

    9.文档与视结构:
    可以认为CView类窗口是CMainFrame类窗口的子窗口。
    CDocument类是文档类。
    DOC-VIEW结构将数据本身与它的显示分离开。
    文档类:数据的存储,加载
    视类:数据的显示,修改

    10.文档类,视类,框架类的有机结合:

    // 在CTestApp类CTestApp::InitInstance()函数中通过文档模板将文档类,视类,框架类组织在一起。
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
    IDR_MAINFRAME,
    RUNTIME_CLASS(CTestDoc),
    RUNTIME_CLASS(CMainFrame), // main SDI frame window
    RUNTIME_CLASS(CTestView));
    AddDocTemplate(pDocTemplate);//增加到文档模板

    11,窗口类,窗口对象,窗口:
    窗口是屏幕上的一块儿矩形区域;窗口类是封装了对窗口的一系列操作的类,比如注册窗口,创建窗口,显示窗口,销毁窗口等等;窗口对象是窗口类的一个实例。

    孙鑫VC++讲座笔记-(3)MFC程序框架的剖析 附1-SDI程序流程图

    //AfxWinMain()函数在WINMAIN.CPP文件中,它主要调用以下函数
    AfxWinInit();
    pApp->InitApplication();    //内部初始化管理
    pThread->InitInstance();    //调用子类中的InitInstance()
    CTestApp::InitInstance();
    ┣━ProcessShellCommand(cmdInfo);        //对命令行进行解释
    ┃        CTestDoc::CTestDoc();        //构造文档类对象
    ┃        CMainFrame::CMainFrame();    //构造框架窗口对象
    ┃            CFrameWnd::LoadFrame();    //WINFRM.CPP
    ┃            ┣━AfxEndDeferRegisterClass();    //WINCORE.CPP,注册窗口类
    ┃            ┃        AfxRegisterClass();    //WINCORE.CPP
    ┃            ┣━CMainFrame::PreCreateWindow();
    ┃            ┃        CFrameWnd::PreCreateWindow();
    ┃            ┃            AfxEndDeferRegisterClass();
    ┃            ┣━AfxRegisterClass();
    ┃            ┗━CFrameWnd::Create();        //创建CMainFrame窗口
    ┃                    CWnd::CreateEx();
    ┃                        CMainFrame::PreCreateWindow();
    ┃                            CFrameWnd::PreCreateWindow();
    ┃                        CTestView::CTestView();    //构造CTestView对象
    ┃                        CWnd::CreateEx();        //创建CTestView窗口
    ┃                            AfxEndDeferRegisterClass();
    ┃                        AfxEndDeferRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CToolBar工具栏
    ┃                        AfxEndDeferRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CStatusBar状态栏
    ┃                        AfxEndDeferRegisterClass();
    ┃                            AfxRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CDockBar
    ┃                        AfxEndDeferRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CDockBar
    ┃                        AfxEndDeferRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CDockBar
    ┃                        AfxEndDeferRegisterClass();
    ┃                        CWnd::CreateEx();        //创建CDockBar
    ┣━m_pMainWnd->ShowWindow(SW_SHOW);    //显示窗口
    ┗━m_pMainWnd->UpdateWindow();        //更新窗口
    nReturnCode = pThread->Run();    //进入消息循环
  • 相关阅读:
    Mysql 服务无法启动 服务没有报告任何错误
    mysql国内镜像下载网址
    windows上自动设置java环境变量的脚本
    史上最详细的新浪广告系统技术架构优化历程
    十分钟理解广告系统
    Nginx基础配置指令
    nginx配置详情(总结)
    利用tcpdump抓包工具监控TCP连接的三次握手和断开连接的四次挥手
    Windows7配置QT-Android开发环境!
    一位计算机专业硕士毕业生的求职经历和感想[转载]
  • 原文地址:https://www.cnblogs.com/Key-Ky/p/3536768.html
Copyright © 2020-2023  润新知