zoukankan      html  css  js  c++  java
  • MFC实现原理

    通过VC++ 新建一个MFC单文档应用程序,其工程名为mfcproject.新建后通过类视图可以看到一共有5个类:

    CAboutDlg:对话框类,如关于对话框

    CMainFrame:应用程序框架类,包括工具栏菜单等

    CMfcprojectApp:应用程序类

    CMfcprojectDoc:文档类

    CMfcprojectView:也是和文档有关的视图类

    1、mfcproject.cpp文件中定义了全局类 CMfcprojectApp theApp;在这个地方设置断点,调试运行可以发现整个程序首先执行到这个地方。

    2、全局变量定义后将会调用CMfcprojectApp 类的构造函数

    3、从mfcproject.h中可以发现 CMfcprojectApp继承自CWinApp类(在APPCORE.cpp中),根据继承性原理,程序将会首先调用CWinApp类的构造函数,如果细心地话会发现CWinApp的构造函数有参数,但CMfcprojectApp类构造函数并没有带参数,这是怎么回事呢?再仔细看下CWinApp类的构造函数:CWinApp(LPCTSTR lpszAppName = NULL); 看见了没这里的参数是默认值,这也就是为什么CMfcprojectApp构造函数没有带参数的缘故了

    4、定义好全局变量以后,就要找主函数入口了,MFC程序的主函数入口为:

    extern "C" int WINAPI
    _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPTSTR lpCmdLine, int nCmdShow)
    {
        // call shared/exported WinMain
        return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
    }

    该函数在APPMODUL.cpp中,从这个函数可以看出真正的入口函数应该为AfxWinMain(Winmain.cpp中)

    int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPTSTR lpCmdLine, int nCmdShow)
    {
        ASSERT(hPrevInstance == NULL);


        int nReturnCode = -1;
        CWinThread* pThread = AfxGetThread();
        CWinApp* pApp = AfxGetApp(); //获取子类


        // AFX internal initialization
        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
            goto InitFailure;


        // App global initializations (rare)
        if (pApp != NULL && !pApp->InitApplication())
            goto InitFailure;


        // Perform specific initializations
        if (!pThread->InitInstance()) //初始化注册窗口
        {
            if (pThread->m_pMainWnd != NULL)
            {
                TRACE0("Warning: Destroying non-NULL m_pMainWnd ");
                pThread->m_pMainWnd->DestroyWindow();
            }
            nReturnCode = pThread->ExitInstance();
            goto InitFailure;
        }
        nReturnCode = pThread->Run(); 

    关键的语句是line8获取子类实例,line19初始化子类,完成窗口注册,line20可以在这些行上设置断点

    5、 由于pThred当前指向子类,InitInstance函数是虚函数,因此 pThread->InitInstance()将调用子类的CMfcprojectApp::InitInstance()


    InitFailure:
    #ifdef _DEBUG
        // Check for missing AfxLockTempMap calls
        if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
        {
            TRACE1("Warning: Temp map lock count non-zero (%ld). ",
                AfxGetModuleThreadState()->m_nTempMapLock);
        }
        AfxLockTempMaps();
        AfxUnlockTempMaps(-1);
    #endif


        AfxWinTerm();
        return nReturnCode;
    }


    BOOL CMfcprojectApp::InitInstance()


     {
       AfxEnableControlContainer();


       // Standard initialization
       // If you are not using these features and wish to reduce the size
       //  of your final executable, you should remove from the following
       //  the specific initialization routines you do not need.

    #ifdef _AFXDLL
       Enable3dControls();            // Call this when using MFC in a shared DLL
    #else
       Enable3dControlsStatic();    // Call this when linking to MFC statically
    #endif

       // Change the registry key under which our settings are stored.
       // TODO: You should modify this string to be something appropriate
       // such as the name of your company or organization.
       SetRegistryKey(_T("Local AppWizard-Generated Applications"));

       LoadStdProfileSettings();  // Load standard INI file options (including MRU)

       // Register the application's document templates.  Document templates
       //  serve as the connection between documents, frame windows and views.

     
     CSingleDocTemplate* pDocTemplate;
       pDocTemplate = new CSingleDocTemplate(
           IDR_MAINFRAME,
           RUNTIME_CLASS(CMfcprojectDoc),
           RUNTIME_CLASS(CMainFrame),       // main SDI frame window
           RUNTIME_CLASS(CMfcprojectView));
       AddDocTemplate(pDocTemplate);//新建一个单文档的模板,并将 doc,view,frame类添加到该模板中。


       // Parse command line for standard shell commands, DDE, file open
       CCommandLineInfo cmdInfo;
       ParseCommandLine(cmdInfo);

       // Dispatch commands specified on the command line
       if (!ProcessShellCommand(cmdInfo))//窗口的注册(不太确定)
           return FALSE;


       // The one and only window has been initialized, so show and update it.
     
     m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口
       m_pMainWnd->UpdateWindow();//更新窗口 

       return TRUE;

     }

    上述代码中红色部分是比较重要的地方,可以在这些地方设置断点。

     6、窗口注册会调用函数BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)在文件WINCORE.CPP中

     7、紧接着调用BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs),创建窗口

    BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
    {
       if( !CFrameWnd::PreCreateWindow(cs) )
           return FALSE;
       // TODO: Modify the Window class or styles here by modifying
       //  the CREATESTRUCT cs
       //此处修改cs,实现用户自定义窗口
       return TRUE;
    }

    8、接下来调用line3父类的precreatewindow函数

    9、由于窗口包括frame框架类,因此需要调用cfrmwnd的create函数(WINFRM.cpp中),这个函数又会调用Cfrmwnd的父类CWnd::CreateEx函数

    10、注册完窗口后就会执行消息响应,消息响应是通过  AfxWinMain中nReturnCode = pThread->Run()实现的

    11、用一个dowhile循环实现消息循环    PumpMessage()

    大概的MFC实现就写到这,可能有很多不对的地方,等熟悉以后再来更新!


  • 相关阅读:
    开源爬虫综述
    html页面工具-htmlUnit
    Html JavaScript网页制作与开发完全学习手册
    移动互联网之路-李晓斌
    算法图解
    游戏编程算法与技巧
    一秒解决CentOS下service 功能 不能使用 bash: service: command not found
    LINUX企业应用案例精解 第2版 李晨光
    深入分析GCC
    嵌入式LINUX基础教程 第2版
  • 原文地址:https://www.cnblogs.com/AlexanderZhao/p/12879002.html
Copyright © 2011-2022 走看看