• VC++学习(0):MFC框架


    讲述MFC AppWizard的原理与MFC程序框架的剖析。AppWizard是一个源代码生成工具,是计算机辅助程序设计工具,WinMain在MFC程序中是 如何从源程序中被隐藏的,theApp全局变量是如何被分配的,MFC框架中的几个类的作用与相互关系,MFC框架窗口是如何产生和销毁的,对窗口类的 PreCreateWindow和OnCreate两个函数的着重分析,Windows窗口与C++中的CWnd类的关系。
    1,寻找WinMain入口:
      在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。
      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)
    调 试:CWinApp::CWinApp();->CTestApp theApp;(->CTestApp ::CTestApp())->CWinApp::CWinApp()->CTestApp ::CTestApp()->_tWinMain(){}

    4,_tWinMain函数中通过调用AfxWinMain()函数来完成 它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成, 我们可根据这些类函数来设计自己的应用程序)。
      AfxWinMain()函数在WINMAIN.CPP中:
      在AfxWinMain()函数中:
      (1)CWinApp* pApp = AfxGetApp();
        说明:pApp存储的是指向WinApp派生类对象(theApp)的指针。
        //_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
        // { return afxCurrentWinApp; }

      (2)调用pApp->InitApplication():MFC类的一些内部初始化管理。

      (3)调用pThread->InitInstance()
        说明:pThread也指向theApp,由于基类中virtual BOOL InitInstance()定义为虚函数,所以调用pThread->InitInstance()的时候,调用的是派生类CTestApp的InitInstance()函数。

      (4)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;

        //在创建窗口之前让用户有机会对style进行修改,即修改cs


        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结构体成员来修改所要的窗口外观。

    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,窗口类,窗口对象,窗口:
      窗口是屏幕上的一块儿矩形区域,是一种计算机资源;窗口类是封装了对窗口的一系列操作的类,比如注册窗口,创建窗口,显示窗口,销毁窗口等等;窗口对象是窗口类的一个实例。

  • 相关阅读:
    [CentOS] SSH 免密钥登录
    [WPF] Wait for a moment.
    [Tool] Open Live Writer 插件更新
    [Tool] 博客园的 SyntaxHighlighter 代码高亮
    [Tool] Open Live Writer插件开发
    [Oracle] Bulk Insert Data
    [C1] C1ComboBox 的非编辑状态优化
    CentOS7用阿里云Docker Yum源在线安装Docker 17.03.2
    什么时候该用readfile() , fread(), file_get_contents(), fgets()?
    Aliyun OSS Nginx proxy module(阿里云OSS Nginx 签名代理模块)
  • 原文地址:https://www.cnblogs.com/forlina/p/2120938.html
Copyright © 2020-2023  润新知