MFC程序框架剖析(孙鑫VC++第三讲详解)

转自:http://www.cnblogs.com/Key-Ky/p/3536768.html

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

继承关系:CTestApp:CWinApp:CWinThread:CCmdTarget

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(){}(入口)

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指针是属于基类还是派生类呢?(答案:派生类)

执行顺序为:

CWinApp::CWinApp();->CTestApp theApp;->CTestApp ::CTestApp();->CWinApp::CWinApp();->CTestApp ::CTestApp();->_tWinMain(){}

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

AfxWinMain()函数在WinMain.cpp中:
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)<pre class="cpp" name="code">    // virtual CWinApp::InitApplication()在AppCore.cpp中有实现,是一个虚函数。
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));
...
}
<span style="color: #ff0000;">BOOL PeekMessage(,,,,)函数说明</span>
<span style="color: #ff0000;">The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure.</span>
<span style="color: #ff0000;">If a message is available, the return value is nonzero.</span>
<span style="color: #ff0000;">If no messages are available, the return value is zero.</span>

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;
}

10.文档与视结构:

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

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

// 在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);//增加到文档模板

12.窗口类,窗口对象,窗口:

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

附孙鑫VC++讲座三-MFC程序框架的剖析 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();    //进入消息循环

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
孙鑫vc是一种特殊的混合编程语言,它结合了C语言和Verilog语言的特点。在深入详解孙鑫vc代码之前,我们先了解一下它的一些特性。 首先,孙鑫vc具有高度的可定制性。用户可以根据自己的需求选择C语言和Verilog语言中的特性来编写代码。这种灵活性使得孙鑫vc可以适用于不同的应用领域。 其次,孙鑫vc支持并行计算。它提供了一种简单而有效的方式来利用硬件资源进行并行计算,提高程序的执行效率。 另外,孙鑫vc还具有强大的调试功能。它能够在运行时对代码进行监控和调试,帮助开发者快速定位问题并进行修复。 深入详解孙鑫vc代码包括以下几个方面: 首先,我们可以从代码的结构和组织方式入手。孙鑫vc代码一般由多个模块组成,每个模块包含了各自的功能和接口。 其次,我们需要了解代码中使用的变量和数据类型。在孙鑫vc中,可以使用C语言和Verilog语言中的数据类型,如整型、浮点型等。了解这些数据类型的使用方法和限制对理解代码非常重要。 然后,我们需要分析代码中的控制流和算法。这包括了代码中的条件语句、循环语句等,以及算法的实现细节。通过对控制流和算法的分析,我们可以更好地理解代码的逻辑和实现原理。 最后,我们还需要关注代码中的接口和数据传输方式。在孙鑫vc中,模块之间通过接口进行数据的传递和交互。了解接口的定义和使用方式对于理解代码的功能和模块之间的关系非常重要。 综上所述,深入详解孙鑫vc代码需要从代码的结构和组织方式、变量和数据类型、控制流和算法、接口和数据传输方式等多个方面进行分析和理解。通过对这些方面的研究,我们可以更好地理解孙鑫vc代码,并且能够对代码进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值