MFC代码架构分析

MFC是微软提供给我们的基础类库,是一套面向对象的函数库,以类的方式提供给我们使用。
利用这些类,可以有效地帮助我们完成基于Windows的应用程序的开发。
里面同样有很多全局函数用于类之间的操作调用。
MFC应用程序框架说明
打开创建的Hello工程的工作区,可以看到系统在生成应用程序框架的过程中,自动生成了以下几个类:
CHelloApp
CMainFrame//不变
CHelloView
CHelloDoc
CAboutDlg
(1)CHelloApp类
CHelloApp的基类为CWinApp。如果需要创建MFC应用程序,首先要使用CWinApp类,因为CWinApp类不仅代表了程序中运行的主线程,而且代表了应用程序本身。在任何MFC应用程序中只有一个CWinApp对象,用于控制应用程序的初始化、启动应用程序、运行主消息循环、终止应用程序。
(2)CMainFrame类
类CMainFrame的基类为CFrameWnd,是一个框架窗口。主框架窗口类负责标题栏、菜单栏、工具栏及状态栏的生成。事实上,这些子窗口可以按照用户的意图自定义,只需要修改主框架窗口的实现文件即可。
(3)CHelloView和CHelloDoc类
CHelloView类的基类为CView,而CHelloDoc类的基类为CDocument。之所以把CHelloView类和CHelloDoc类一起介绍是因为这两个类是密切相关的。
视图是显示文档数据的界面,它主要占据着主框架窗口的客户区,视图类不仅把程序文档数据显示出来,它还能接受用户的输入、编辑。视图对象也通过消息与主框架、文档对象相互操作。
文档对象是存储程序数据的地方。一般来说,把要存储的数据放到文档对象中,即把要存储的数据作为文档对象的成员变量,进而实现文档的串行化。
4             查找
找到安装目录->vc98->MFC->Src(MFC的部分源代码)   搜索
(1)        search WinMain
APPMODUL.CPP
#define _tWinMain   WinMain
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          LPTSTR lpCmdLine, int nCmdShow)
{
    // call shared/exported WinMain
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
WinMain设置断点,进行调试
(2)CXXApp构造函数设置断点  产生实例(唯一的)   首先运行构造函数
// The one and only CHelloApp object

CHelloApp theApp;
---父类构造,本类构造

(3)CHelloApp的基类CWinApp    把框架;里面的类和自己要写的类关联在一起
APPCORE.CPP
Ctr+F  查找CwinApp  +F3
构造函数

CWinApp::CWinApp(LPCTSTR lpszAppName)
{
    if (lpszAppName != NULL)
        m_pszAppName = _tcsdup(lpszAppName);
    else
        m_pszAppName = NULL;
    // initialize CWinThread state
    AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
    AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
    ASSERT(AfxGetThread() == NULL);
    pThreadState->m_pCurrentWinThread = this;
    ASSERT(AfxGetThread() == this);
    m_hThread = ::GetCurrentThread();
    m_nThreadID = ::GetCurrentThreadId();

    // initialize CWinApp state
    ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
    pModuleState->m_pCurrentWinApp = this;
    ASSERT(AfxGetApp() == this);

    // in non-running state until WinMain
    m_hInstance = NULL;
    m_pszHelpFilePath = NULL;
    m_pszProfileName = NULL;
    m_pszRegistryKey = NULL;
    m_pszExeName = NULL;
    m_pRecentFileList = NULL;
    m_pDocManager = NULL;
    m_atomApp = m_atomSystemTopic = NULL;
    m_lpCmdLine = NULL;
    m_pCmdInfo = NULL;

    // initialize wait cursor state
    m_nWaitCursorCount = 0;
    m_hcurWaitCursorRestore = NULL;

    // initialize current printer state
    m_hDevMode = NULL;
    m_hDevNames = NULL;
    m_nNumPreviewPages = 0;     // not specified (defaults to 1)

    // initialize DAO state
    m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

    // other initialization
    m_bHelpMode = FALSE;
    m_nSafetyPoolSize = 512;        // default size
}
(4) search 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\n");
            pThread->m_pMainWnd->DestroyWindow();
        }
        nReturnCode = pThread->ExitInstance();
        goto InitFailure;
    }
    nReturnCode = pThread->Run();

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

    AfxWinTerm();
    return nReturnCode;
}
在子类的初始化函数中  把几个类绑定在一起
// 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(CHelloDoc),
    RUNTIME_CLASS(CMainFrame),       // main SDI frame window
    RUNTIME_CLASS(CHelloView));
AddDocTemplate(pDocTemplate);

在子类的初始化函数中 还有
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

(5)search AfxEndDeferRegisterClass  用于注册类
WINCORE.CPP find AfxEnd 1.已经设计好窗口类
find AfxRegisterClass 2.注册窗口类
frame窗口 view窗口
CMainFrame PreCreateWindow设置断点
(6)search CFrameWnd::PreCreateWindow
WINFRM.CPP find CFrameWnd::PreCreateWindow
(7) search CreateEx
WINCORE.CPP CreateEx设置断点
WINFRM.CPP Create设置断点
(8)search CWinThread::Run
THRDCORE.CPP
PumpMessage() 消息循环 设置断点

文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer模式的具体实现框架之一, Document/View Architecture通过将数据和其表示分开,提供了很好的数据层次和表现层次的解耦。然而, 虽然我们使用MFC AppWizard就可以很轻松地获得一个支持Document/View Architecture的MFC程序框架, Document/View Architecture本身的复杂性加上VC产生的一系列代码足够让我们眼花缭乱,一时陷入云里雾里不可自拔。 加上我们更多的人都没有经过Windows SDK Programming 的学习和经历就直接进行MFC Programming的学习和开发, 更是面对一堆的代码不知所措。 之于Document/View Architecture,侯捷先生的《深入浅出MFC》一书确实进行了很深入的分析和研究,网络上也有很多在侯捷先生著述 的基础上的进一步的文章出现,但是个人觉得这里面有一点瑕疵(仅代表k_eckel浅见):太过深入, 这些分析和研究都最终会定位到Windows SDK中窗口的创建过程、MFC中对Document/View Architecture支持所提供的复杂无序的宏等 对于没有Windows SDK Programming 经验和经历的学习者和对于MFC不是很熟悉的学习者无异于是徒增烦恼,一个本来就很复杂的问题 更加地复杂化了。我的观点是这个过程是必要的,然而不是每个人所必需的,或者说不是每个人在初期学习和绝大多数项目开发中所 必需的。我向来对众多的仅仅学会了拖拉点拽就以为会了MFC(侯捷先生在《深入浅出MFC》一书中对这个群体有一个照面,这里不罗嗦) 不以为然,但是我依然认为轻量级学习成本是重要的,容易上手,易于接受是一门技术成功或者说有价值的一个很大的决定性因素。 因此提供一个轻量级的学习过程对于学习来说是很有必要性的,本系列文章就遵循这样一个理念,对MFC中Document/View Architecture 进行一个分析(姑且也可以称之为深入),尽量将对Document/View Architecture的理论研究(侯捷先生书中很多内容)和实际的项目 开发结合起来,最后提供一个简单但是全面的Document/View Architecture项目开发(主要是界面框架设计和开发)的实际例子,供参考。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值