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 = -;
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(); //进入消息循环
MFC学习-第2,3课 MFC框架的运行机制的更多相关文章
- ASP.NET MVC 学习1、新增Controller,了解MVC运行机制
1,turorial ,根据链接教程新建一个MVC项目 http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/ ...
- JVM学习001通过实例总结Java虚拟机的运行机制
JVM学习(1)——通过实例总结Java虚拟机的运行机制-转载http://www.cnblogs.com/kubixuesheng/p/5199200.html 文章转载自:http://www.c ...
- 深入浅出MFC学习笔记 第三章 MFC六大关键技术之仿真
0:MFC类层次结构 1:MFC程序的初始化过程CWinApp::InitApplication()CMyWinApp::InitInstance()CMyFrameWnd::CMyFrameWnd( ...
- 新人学习微信小程序开发之框架篇
大家好我是智哥,一名专注于前端领域的一名码农. 咱们今天主要来说说微信小程序, 最近一段时间微信群里的小程序,小游戏各种分享是突然一下子就爆发了,现在来看小程序作为微信的重磅功能无疑又是下一个风口.咱 ...
- Web框架——XWAF的代码结构和运行机制(4)
XWAF是一套基于Servlet和java反射技术的Web应用程序框架,它利用Servlet运行机制在服务器上加载和运行,接管客户端请求,依靠ServletRequest对象获取用户请求信息,使用Se ...
- MFC学习-第4课 消息机制和MFC作图
转自: 1.http://blog.sina.com.cn/s/blog_6b5180bf01012kbz.html 2.http://blog.csdn.net/happyhhb/article/d ...
- MFC学习-第一课 MFC运行机制
最近由于兴趣爱好,学习了孙鑫的MFC教程的第一课.看完视频了,自己便用visual studio 2010尝试了MFC编程,其中遇到了一些问题. 1.vs2010不像vs6.0那样可以新建一个空的MF ...
- 第四课——MFC应用程序框架
一.MFC应用程序类型 上篇文章的彩蛋:可通过使用MFC应用程序向导(MFC AppWizard)的功能来创建所需要的应用程序,这意味着不需要输入任何代码.MFC除了应用程序向导,还对应用程序项目有着 ...
- 我的MFC学习之路(一)
因为项目需求,我开始应用MFC写程序.具体接触MFC的时间大概也有两个月了.现在的水平算是刚刚踏入了MFC大门的半只脚.目前能基本使用MFC Class Wizard,可以根据实例仿照完成需求,小范围 ...
随机推荐
- JavaScript学习笔记-简单的计时钟表
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...
- AngularJS引入Echarts的Demo
最近要用到图表展示,想了想,还是首选Echarts,HighCharts和D3.js备用吧, 而项目中也用到了AngularJS,所以需要把Echarts引入到AngularJs中一起使用, 试了试, ...
- T4模板——一个神奇的代码生成器
利用T4模板,可以很方便的从数据库映射成Model模型,相当于动软等功效.但动软是可以直接生成三层,抽象工厂的,T4没那么牛叉,所以我们一般只用作生成Modle或者Server等指定方法了. 废话少说 ...
- SQL-Server下载地址
有同学费尽心思的找SQL server数据库各版本的下载地址,看到别人的求助贴就不自觉的想去帮助他们,但是一个一个去帮助又不太现实,毕竟个人精力有限,既然大家有需求,那么艾薇百科今天就本着乐于分享和奉 ...
- 【JavaEE企业应用实战学习记录】struts国际化
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2016/10/6 Time: 16:26 To change this tem ...
- android 调用电话功能
今天用到了打电话的功能,这要如何实现呢? 很简单 1.创建对应对的xml展示页面喝java文件 2.在manifest中添加权限 下面上代码吧: 这是布局的一部分 <LinearLayout a ...
- Bete冲刺第六阶段
Bete冲刺第六阶段 github:https://github.com/RadioGroup/JourneyHelper 今日工作: web: 陈灿:新增了用户信息更新接口,优化了部分接口逻辑,更新 ...
- jQuery基础--样式篇(1)
1.jQuery简介:JQuery是继prototype之后又一个优秀的Javascript库.它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF 1.5+, Safari ...
- Android PNG透明图片转JPG格式背景变黑
Android PNG透明图片转JPG格式背景变黑 在上传图片是,需要把PNG格式转换成JPG格式的,但是在遇上透明背景时,转过来就变成黑色底图了! 原因是PNG支持透明图而 JPG格式不支持透明底 ...
- DOCTYPE是什么鬼?文档模式又是什么鬼?
!DOCTYPE !DOCTYPE是什么: 在所有 HTML 文档中规定 DOCTYPE 是非常重要的,这样浏览器就能了解预期的文档类型, 告诉浏览器要通过哪一种规范(文档类型定义 DTD)解析文档( ...