mfc编程 孙鑫_孙鑫VC++视频教程笔记-(3)MFC程序框架的剖析 附1-SDI程序流程图

1,寻找WinMain人口:

在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。

路径:MFC|SRC|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函数加载的时候,已经为全局对象或全局变量分配了内存和赋初值。

所以:CTEApp theApp;->CTEApp ::CTEApp(){}->_tWinMain(){}

说明:每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身

。在WIN32程序当中,表示应用程序是通过WINMAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。在基于MFC应用

程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。

3,通过构造应用程序对象过程中调用基类CWinApp的构造函数,在CWinApp的构造函数中对程序包括运行时一些初始化工作完成了。

CWinApp构造函数:MFC|SRC|APPCORE.CPP

CWinApp::CWinApp(LPCTSTR lpszAppName){...}//带参数,而CTEApp构造函数没有显式向父类传参,难道CWinApp()有默认参数?见下:

(在CWinApp类定义中,CWinApp(LPCTSTR lpszAppName = NULL);)

注意:CWinApp()函数中:

pThreadState->m_pCurrentWinThread = this;

pModuleState->m_pCurrentWinApp = this

(this指向的是派生类CTEApp对象,即theApp)

调试:CWinApp::CWinApp();->CTEApp theApp;(->CTEApp ::CTEApp())->CWinApp::CWinApp()->CTEApp ::CTEApp()->_tWinMain(){}

4,_tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序

框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。

AfxWinMain()函数路径:MFC|SRC|WINMAIN.CPP:

在AfxWinMain()函数中:

CWinApp* pApp = AfxGetApp();

说明:pApp存储的是指向WinApp派生类对象(theApp)的指针。

//_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()

// { return afxCurrentWinApp; }

调用pThread->InitInstance()

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

派生类CTEApp的InitInstance()函数。

nReturnCode = pThread->Run();

说明:pThread->Run()完成了消息循环。

5,注册窗口类:AfxEndDeferRegisterClass();

AfxEndDeferRegisterClass()函数所在文件:MFC|SRC|APPCORE.CPP

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){...}

说明:设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。

调试:

CWinApp::CWinApp();->CTEApp theApp;(->CTEApp ::CTEApp())->CWinApp::CWinApp()->CTEApp ::CTEApp()->_tWinMain(){}//进入程序

->AfxWinMain();->pApp->InitApplication();->pThread->InitInstance()//父类InitInstance虚函数;

->CTEApp::InitInstance()//子类实现函数;

->AfxEndDeferRegisterClass(LONG fToRegister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在PreCreateWindow中进行注册

)//之后进入创建窗口阶段(以下再不做调试)

6,PreCreateWindow()://主要是注册窗口类

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CFrameWnd::PreCreateWindow(cs) )

return FALSE;

return TRUE;

}

说明:

CFrameWnd::PreCreateWindow()函数所在文件:MFC|SRC|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 VERIFY(f) ASSERT(f)

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

define AFX_WNDFRAMEORVIEW_REG 0x00008

const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;//WINCORE.CPP文件中,定义为全局数组。

//#define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView")

7,创建窗口:

Create()函数路径:MFC|SRC|WINFRM.CPP:

CFrameWnd::Create(...){

...

CreateEx(...);//从父类继承来的,调用CWnd::CreateEx().

...

}

CWnd::CreateEx()函数路径:MFC|SRC|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,显示和更新窗口:

CTEApp类,TEApp.cpp中

m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口,m_pMainWnd指向框架窗口

m_pMainWnd->UpdateWindow();//更新窗口

说明:

class CTEApp : 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()方法路径:MFC|SRC|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;

}

10,文档与视结构:

可以认为View类窗口是CMainFram类窗口的子窗口。

DOCument类是文档类。

DOC-VIEW结构将数据本身与它的显示分离开。

文档类:数据的存储,加载

视类:数据的显示,修改

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

在CTEApp类CTEApp::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。...

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CTEDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CTEView));

AddDocTemplate(pDocTemplate);//增加到模板...

----------------------------------------------------------------------------->

//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(); //进入消息循环

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每天一个linux命令(性能、优化):【转载】free命令

free命令可以显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。在Linux系统监控的工具中,free命令是最经常使用的命令之一。 1.命令格式: free [参数] 2.命令功能: free 命令显示系统使用和空闲…

gitee存放代码_git / gitee 提交本地仓库代码到Git或Gitee流程 及 常见报错

前提:在 Windows 下安装 git 客户端然后直接在 base 中执行命令1、本地初始化 git 设置git config --global user.name "你的名字或昵称"git config --global user.email "你的邮箱"2、进入项目文件夹,初始化目录 --通过命令 git in…

mysql可以存文档_MySQL 文档存储介绍

MySQL 文档存储 可以跳过底层数据结构创建、数据规范化和其它使用传统数据库时需要做的工作,直接存储数据。MySQL 可以提供 NoSQL JSON 文档存储Document Store了,这样开发者保存数据前无需规范化normalize数据、创建数据库,也无需在开发之前…

Maven项目配置、检出、运行

副标题:JDK安装到Maven运行 关键字:JDK SVN Maven Tomcat Eclipse IDEA 一、JDK 1、JDK包 JDK包 ../Java/jdk1.8 # 按需 图例 2、环境变量 步骤 计算机 → 属性 → 高级系统设置 → 环境变量 → 系统变量 → 新建/编辑 设置 JAVA_HOME ..…

mysql 存储过程代码_MySQL存储过程及常用函数代码解析

mysql存储过程的概念:存储在数据库当中可以执行特定工作(查询和更新)的一组SQL代码的程序段。mysql函数的概念:函数是完成特定功能的SQL语句,函数分为内置函数和自定义函数(user-defined function UDF)MySQL存储过程和函数的区别存储过程可以…

MySQL数据库恢复(使用mysqlbinlog命令)

1:开启binlog日志记录 修改mysql配置文件mysql.ini,在[mysqld]节点下添加 复制代码代码如下:# log-bin log-bin E:/log/logbin.log 路径中不要包含中文和空格。重启mysql服务。通过命令行停止和启动mysql服务 复制代码代码如下:c:\>net stop mysql…

mysql 创建数据库文件_mysql学习之通过文件创建数据库以及添加数据

1、# 创建数据库语句create database mydb default character set utf8;# 运用数据库语句use mydb;# 创建表格,这里只简单的创建一张表格# 设置InnoDB主要是为了事务操作的需要create table mytable(id int primary key auto_increment,name varchar(20),count int …

angularjs启动项目报ERROR in AppModule is not an NgModule解决方法

这主要是ts编译器版本问题,一般是因为ts编译器版本过高导致。 解决方式: npm uninstall -g typescriptnpm install -g typescripttsc -v 查看安装的typescript版本修改package.json中的typescript版本为当前电脑所安装版本 删除node_module重新安装cnpm …

mysql gtid 备份恢复_MYSQL数据库备份恢复

在实例存活的情况,可以在实例状态中查询ALL_GTID。在实例崩溃的情况,无法在实例状态中查询ALL_GTID。可以通过查询BINLOG中的Previous-GTIDs计算来获得ALL_GTID。下面列举与ALL_GTID相关的变量。与ALL_GTID相关的变量Previous-GTIDsPrevious-GTIDs格式如…

PMP 笔记

项目: 为创造独特的产品、服务或结果而进行的临时性工作。 项目特征: 独特性:Unique、临时性:Temporary、渐进明细。 渐进明细:预算越来越精细。比如三峡工程中,预算从10亿级的误差到1亿误差,再…

在mysql怎样查询地址和电话_Mysql数据查询

Mysql查询数据多次过滤条件:from、where、group by、having、distinct、order by、limit > 层层筛选后的结果查:select [distinct] 字段1 [[as] 别名1],...,字段n [[as] 别名n] from [数据库名.]表名 [条件];注:一条查询语句,可…

谷歌搜索技巧:搜索语法+隐藏彩蛋+高级设置

Google是一个非常精密成熟的搜索引擎,其搜索结果的丰富性和准确度较其他搜索引擎都要好,但大多数用户都还只是停留在搜索框中输入一两个关键字,然后点击“搜索”按钮的阶段,这一过程是非常低效和无谓的。学习一些搜索引擎常用的搜…

mysql如何给表字段加密_Mysql 字段加密

1、PASSWORD()2、ENCODE(,) DECODE(,)3、MD5()4、SHA5()5、AES_ENCRYPT AES_DECRYPT加密 select aes_encrypt(name, password );解密 select aes_decrypt(aes_encrypt(name, password ), password );可用hex或base64转码(base64在mysql5.6及以上支持)select hex(aes_en…

mysql数据类型支持比较运_Mysql支持的数据类型(总结)

一.数值类型Mysql支持所有标准SQL中的数值类型,其中包括严格数据类型(INTEGER,SMALLINT,DECIMAL,NUMBERIC),以及近似数值数据类型(FLOAT,REAL,DOUBLE PRESISION),并在此基础上进行扩展。扩展后增加了TINYINT,MEDIUMINT,BIGINT这3种长度不同的整形&#x…

Java 面向对象的设计思维

面向对象的设计思维:合适的方法应该出现在合适的类里面 |解释|:方法是哪个类的,方法便在哪个类里,由这个类去调用 |实际应用|:基本数据类型包装类:因为想要对基本类型数据进行更多的操作,最方便的方式就是将其封装成对象.在对象的描述中定义更多的属性和…

i5 1135g7什么水平_i7-10510U和i5-1135G7对比,该怎么选择呢?

导读:新旧笔记本交替,intel十代i7是否还有与十一代i5一战之力?两者之间差距多少呢?作为买家,肯定想要了解下的哈!! 参数对比 对比项i7-10510U的参数i5-1135G7的参数CPU主频1.8GHz2.4GHz最高睿频4.9GHz4.2GHz三级缓存8MB8MBC/T四核八线程四核八线程核显频率1.15GHZ1.3GHZ…

《学习心得》

最近在学习设计模式,正好也要做毕业设计,就想着把学到的一些皮毛用到毕业设计上面去,结果真的是无从下手。也看了很多其他人关于设计模式的博客,讲了很多很多的好处,但是就是不知道该怎么样运用到实际的项目上去。 毕业…

java获取硬盘序列号_Win7 64+Python3.7获取计算机硬盘信息初探

一、需求由于最近负责电脑资产清查的工作,有100多台分散的电脑需要获得用户名、MAC地址、硬盘序列号、硬盘品牌一般方法:(1)查看系统用户名(2) 获取MAC地址 windos命令行使用ipconfig /all(3&am…

js for in 获得遍历数组索引和对象属性

for in 遍历对象属性 获取的是对象的属性名 var person { name:"admin", age:"21", address:"shanghai"};for(var i in person){ console.log(i)}结果 取得对象的属性名 for in 获取数组的索引值 var array [admin,manager,db];for(var i in arr…

mysql数据库诊断_RDS MySQL 数据库全量SQL诊断

三大难点问题使用MySQL数据库的用户,不可避免都会遇到下面三个难题:1、历史问题难定位数据库凌晨3点发生了CPU 100%的告警,但是该时间段却没有任何慢SQL,怎么继续查找原因?2、SQL压测模版难获取下周要进行大促压测&…