DIY一个MFC程序

前面剖析了MFC的基本框架:


1.通过定义一个CXXX(项目名)App类的全局对象theApp启动应用程序(在进入WinMain函数之前)

       具体就是在定义theApp对象时自动调用了CXXXApp类的构造函数,同时根据C++继承的原理,调用前会先调用其基类CWinApp构造函数。完成一些初始化工作,注意的是这里把theApp对象保存在了属于m_pCurrentWinApp中。


2.接着进入WinMain函数(实际上由AfxWinMain来实现),通过InitApplication,InitInstance、Run三个函数完成窗口类选择、注册并建立窗口,显示、更新窗口,建立消息循环

       具体就是在AfxWinMain中通过AfxGetApp,AfxGetThread函数把m_pCurrentWinApp中保存的theApp对象赋给pApp和pThread,然后pApp->InitApplication()完成MFC内部管理工作,pThread->InitInstance()完成注册窗口类,创建窗口等工作,pThread->Run()完成消息循环的建立。


3.接着进入消息循环虽然也设置了默认的窗口过程函数,但实际上是采用了消息映射机制来处理各种消息。当收到WM_QUIT消息时,退出消息循环,程序结束。


        


既然找到了这些封装在底层框架中的Windows API函数,以及对MFC框架有一些理解了,那么通过借助MFC类库的几个类自己应该也能在Win32项目中DIY一个MFC程序。 


首先,用VS2013建立一个名为MFCFrame的Win32空项目,在解决方案资源管理器视窗下在源文件中添加---新建项一个名为MFC的C++文件。

通过前面的剖析可以发现需要建立CWinApp的派生类然后定义这个派生类的对象theApp,还有就是CFrameWnd的派生类(在AfxWinMain中进行窗口相关操作必不可少,这个派生类中的m_pMainWnd用于保存CreateWindow返回的窗口句柄)。


在Win32项目下DIY一个MFC程序:

#include <afxwin.h>   //要用到MFC相关类库

class MyFrame : public CFrameWnd
{
//m_pMainWnd成员变量继承而来,无需定义
public:
	MyFrame()
	{
		MessageBox(TEXT("进入MyFrame构造函数,执行窗口相关工作"), TEXT("MyMFC"), MB_OK);
		Create(NULL, TEXT("MyMFC"));	//调用CFrameWnd::Create,只填两个实参,剩下的用缺省值
	}
};

class MyApp : public CWinApp
{
public:
	MyApp()
	{		
		MessageBox(0, TEXT("退出CWinApp构造函数,已保存theApp对象"), TEXT("MyMFC"), MB_OK);	
	}
	BOOL InitInstance();    //MFC中InitIntance是虚函数,但实际调用的确实是CWinApp派生类的
	BOOL ExitInstance();
};
BOOL MyApp::InitInstance()
{
	MessageBox(0, TEXT("现在在WinMain中,执行InitInstance"), TEXT("MyMFC"), MB_OK);
	MyFrame* pFrame=NULL;
	pFrame = new MyFrame;       //自动调用了MyFrame的构造函数
	m_pMainWnd = pFrame;        //pFrame指针在InitInstance函数结束时析构,转存到m_pMainWnd这个MyFrame类的成员变量中
	pFrame->ShowWindow(SW_NORMAL);
	pFrame->UpdateWindow();
	return TRUE;
};
BOOL MyApp::ExitInstance()
{
	MessageBox(0, TEXT("窗口已销毁,执行ExitInstance结束程序"), TEXT("MyMFC"), MB_OK);
	return TRUE;
};
MyApp theApp;

编译错误了吧。。这里需要在这个项目的属性页里面--配置属性--常规--MFC的使用--在静态库中使用MFC

(或者选择在共享DLL中使用MFC。区别:使用动态链接时可能需要把一些库一起打包,以防止有的机子上没有该库文件或者版本不兼容而出现的库的依赖问题;使用静态链接,会把程序所需的库一起编译,生成的文件可能会大些,但是可执行文件移植时不会出错。


这样就能编译链接成功了~


代码中有很多注释加上前面我的笔记也有剖析,但还是解释一些难理解的地方:

1.第一个MessageBox函数为何只有三个参数(不需要窗口句柄作参数),还有TEXT函数是干什么用的?

首先解释TEXT,我使用的VS2013作IDE,选择的Unicode字符集,Unicode相比于ANSI的好处找本书都有。。这里就不说了。

#ifdef UNICODE

#define MessageBox MessageBoxW   //W表示Wide,宽字符(双字节)

......

而Char*非LPCTSTR类型,使用TEXT转换。

MyFrame类内用的MessageBox函数实际上非_stdcall MessageBox,而是CWnd::MessageBox,定义自然也就不同,CWnd类内有存放窗口句柄的成员变量自然就不需要提交窗口句柄这一参数了~


2.InitInstance是怎么调用的?

这里需要注意的是MFC中WinMain是由编译链接时才加入到程序中的,InitInstance正是在WinMain中被调用,可以找WinMain定义来看。


3.m_pMainWnd怎么来的?有什么用?

在CWinThread里定义:CWnd* m_pMainWnd; 然后继承下来给了CWinApp,还有MyApp。

作用见注释,由于这个变量是线程类的,线程未结束它的生命周期就没结束,没线程了,它就消失,窗体框架也结束。


4.ShowWindow和UpdateWindow为什么没有像Windows SDK编程那样把窗口句柄作参数?

有心的话会注意到这里是用pFrame指针指向的MyFrame类对象来调用这两个函数的,而MyFrame类继承了一个存放窗口句柄的窗口对象(成员变量),调用成员函数时使用本类的成员变量当然是合法的,无需作为参数传递进来。




实验:在MyApp::InitInstance函数中去掉p_MainWnd=pFrame;

结果:窗口当然还是可以生成,只不过在同时(未点击窗口右上方关闭来产生关闭事件,由操作系统包装此事件发送WM_QUIT消息)会出现标识ExitInstance函数用的小MessageBox窗口,就是说窗口刚刚产生完(InitInstance刚刚执行完),窗口对象的生命周期就坑爹的没了。。窗口对象一经析构,窗口自然销毁,执行ExitInstance结束程序。











  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值