帮你快速理解什么是MFC(Windows环境下)

2023-10-26

 ​​​​​​​​​​​​​​​​​​​​​

 我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下的MFC到底是一个什么技术。

早在1998年,MFC绝对是技术界的一个热门名词,现在似乎提的人很少。但其他MFC的很多程序仍在世界上各个角落运行着。做为一名系统架构师,你仍然不能忽视MFC的存在。但后来接触技术的人大多不太了解这个,那我们一起来看看。

大家对VC++ 不陌生,1992年VC++是1.0,集成了MFC2.0。1998年推出了VC++6.0,集成了MFC6.0。2005年是VC++8.0,2009年是VC++9.0,2010年是VC++10.0。

MFC是一个类库,它是VC++的核心,中文叫做微软基础类库。那它是干什么用的呢?程序员可以利用MFC类库实现自己想要的功能,如菜单、工具栏、状态栏的创建,还有窗口的注册、创建与显示、更新功能。针对这些功能,下面详细介绍下窗口类。

MFC应用程序有3种类型,基于单文档、基于多文档、基于对话框。前两种都会有窗口,而第3种的对话框不是窗口。所以学习窗口类对学好MFC至关重要,它也是MFC类库中最基本的。MFC程序员写程序常用的3个类:CRect、CPoint、CString。

这3个类之所以会被经常应用,是因为当被要求在窗口中画一些长方形,或者是限定一个区域。比如,只能在窗口中的某一个方形范围中操作,就要用CRect类来圈定一个范围,同时读者还可以将它的功用衍生到其他领域。而对于CPoint类,一般在系统的开始界面中,都会贴一张图片以示美观,但是确定图片的放置位置就是确定左上角和右下角点的二维坐标值。因此这时位置点的坐标值至关重要,而CPoint类就可以创建这样一个对象,它可以定义一个点的二维坐标值。最后说说CString类,它就是将C++中的对string的各种操作封装起来变成一个只能在MFC下使用的类。在MFC中用CString当然要比直接用string省事多了。而它经常被运用的场合,就是当一个项目的开始界面中要显示一段文字时,需要在内存中声明一个CString对象来存储这段文字的值。

经常用到的控件编程中,有一种控件是静态文本编辑框。当用户输入信息时,程序必须实时地获取编辑框中的信息,而此信息就需要被存放到一个变量中。由于获取编辑框中文本信息的函数决定了这个变量的类型必须是CString类型的,因此熟悉它的应用也就是情理之中了。
 

1.窗口类WNDCLASS
WNDCLASS结构体包含了所有窗口类的特征,如下是窗口类的原型。

typedef struct {
UINT style;  //窗口类型
WNDPROC lpfnWndProc;  //窗口处理函数
int cbClsExtra;  //窗口类扩展字节
int cbWndExtra;  //窗口实例扩展字节
HINSTANCE hInstance;  //当前实例句柄
HICON hIcon;  //窗口图标
HCURSOR hCursor;  /窗口光标
HBRUSH hbrBackground;  //窗口背景色
LPCTSTR lpszMenuName;  //窗口菜单名
LPCTSTR lpszClassName;  //窗口类名
} WNDCLASS,*PWNDCLASS;  //第一个是实体类型,第二个是指针类型

震惊吗?

Windows环境中的窗口居然就是我们C语言中的结构体!!

两者看似没有关系,居然本质是一样的。

最后一行表明这个结构体既可以被当作一个实体类型来用,也可以作为指针被定义,具体用哪种就要看应用场合了,但经常会被作为实体应用。熟悉它的定义后,下面介绍下它的应用实例,如下代码:

WNDCLASS wndclass;         //创建一个窗口类
wndclass.cbClsExtra=0;  //窗口类无扩展
wndclass.cbWndExtra=0;  //窗口实例无扩展
wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);  //窗口背景为黑
wndclass.hCursor=Loadcursor (NULL,IDC_ARROW);  //窗口采用箭头光标
wndclass.hIcon=LoadIcon (NULL,IDI_APPLICATION);        //窗口的图标为缺省状态
wndclass.hInstance=hInstance;  //当前实例句柄
wndclass.lpfnWndProc=WinHouProc;  //定义窗口处理函数
wndclass.lpszClassName="VC++";  //窗口类为“VC++”
wndclass.lpszMenuName=NULL;  //窗口无菜单
wndclass.style=CS_HREDRAW | CS_PARENTDC;  //设置窗口类型

RegisterClass(&wndclass);  //注册窗口类

HWND hwnd;
hWnd=CreateWindow("VC++","消息机制",WS_OVERLAPPEDWINDOW,
                      .0,0,600,400,NULL,NULL,hInstance,NULL);  //创建窗口

ShowWindow (hwnd,SW_SHOWNORMAL);  //显示窗口
UpdateWindow(hwnd);  //更新窗口

大家看注释就知道程序的意思,前12行重新赋值完窗口类的各种属性,就要注册这个新的窗口类,就像一群小伙打算创业,刚开始有了初步构思决定开个公司,就要去有关部门注册公司以示合法。这里也一样需要注册这个新的窗口类以示在系统内合法。这就有了RegisterClass();这句。

注册窗口类后,这个注册身份还得依附一个实体上。接下来小伙子们就要去找办公地点,而程序员要为窗口类找一个可以依附的窗口,所以就有了第15行的创建窗口。就有了hWnd=CreateWindow();这句。

公司有了办公地点这个实体后,小伙子们就开始营业了,并且时刻关注本领域的销售市场变化,好让辛苦成立的公司运行下去,而MFC的窗口也就是靠着上述最后两句程序存在在你的电脑内。
  
2.CRect类
CRect类是由tagRECT结构派生来。此类包含的成员变量是一个长方形的左上角和右下角的点坐标。它有6个重载的构造函数。下面举例介绍如何创建一个长方形,CRect类的其中一个构造函数如下:

CRect(
int l,  //定义长方形的左上角点的x坐标
int t,  //定义长方形的左上角点的y坐标
int r,  //定义长方形的右下角点的x坐标
int b  //定义长方形的右下角点的y坐标
)

应用如下,它定义了一个左上角在(0,0)、右下角在(10,50)处的长方形。
CRect rect(0,0,10,50);

3.CPoint类
CPoint类由tagPOINT结构派生来。此类的成员变量是点的x和y坐标。它有5个重载的构造函数。CPoint类的其中一个构造函数如下:

CPoint(
int initX,  //点的x坐标值
int initY  //点的y坐标值
)

创建一个位于坐标系中(20,30)处的一个点,代码如下。
CPoint pt(20,30);  

 4.CString类
CString类没有基类,它有6个重载的构造函数。下面代码的作用是取出定义好的一个CString对象的长度。

 CString name="Microsoft";  //定义一个CString对象并赋值
 int name length =0;  //定义一个整型变量,并初始化
 name_length=name.GetLength();  //将名字的长度值存放到整型变量中

好了,说到这里,再让我们来看看visual c++常见应用程序框架,

对于刚入门的读者来说,最常用的工程有4种:

Win32应用程序、

Win32控制台程序、

MFC应用程序、

MFC动态链接库。

我们来一个一个看一下。

一、Win32应用程序(Win32 Application)
首先得声明下Win32 Application的入口函数是WinMain()。另外它是基于Windows平台的32位开发环境开发的应用程序,也是普通的窗口应用程序。因此要有注册窗口、创建窗口、显示窗口、消息处理等动作。
1.创建项目
新建一个Win32 Application 工程,打开VS开发环境,选择“文件—新建—项目...”命令,出现新建项目对话框。左上角“项目类型”选择Visual C++的Win32,其对应的模板选“Win32项目”。左下方的名称可以自己决定,存储位置也是随便定。单击“确定”按钮之后,出现Win32应用程序向导,单击对话框左侧的“应用程序设置”选项,在选项“应用程序类型”中应是“Windows应用程序”。“附加选项”中选中“空项目”复选框,弄好后单击右下方的“完成”按钮。
2.如何编写程序
一个基本的Win32 应用程序要包括两个函数,即WinMain()和实现窗口操作的函数。如果程序员没有写这两个函数,该程序是不会被执行,也不会有窗口出现的。因此介绍下这两个函数的基本形式。
(1)WinMain()函数
这个函数在一个项目中有且只能有一个,下面代码是它的函数体。

int WINAPI WinMain(
    HINSTANCE hInstance,/指向当前实例的句柄
    HINSTANCE hPrevInstance,//指向先前实例的句柄
    LPSTR lpCmdLine, //命令行
    int nCmdShow//显示状态
)
{
...    //具体代码写入区
} 

在这个函数中,首先要创建一个窗口类,然后给这个窗口类的各种属性赋值,之后注册窗口类、显示窗口、更新窗口。这样基本工作已经做好,但最重要的是建立消息的循环,否则窗口是不会时刻显示当前界面的。
(2)实现窗口操作函数
消息循环有了,还得有消息的触发,这就是实现窗口的操作函数,那它的函数定义体如下代码。这里的函数名字可由你随便定,这里用WinConProc()。

LRESULT CALLBACK WinConProc(
    HWND hwnd,  //窗口句柄
    UINT uMsg, //消息标识符
    WPARAM  wParam,   //第一个消息参数
    LPARAM  lParam   //第二个消息参数
)
{
...    //具体代码写入区
} 

3.应用场合
Win32应用程序是针对需要重新编写窗口,觉得MFC的窗口不美观,或者想实地考察下MFC运行原理的程序员使用。


二、Win32控制台程序(Win32 Console Application)
Win32 Console Application的入口函数是mainO,它的运行结果窗口是MS-DOS的样子,因为它是基于DOS平台开发的应用程序。
1.创建项目
不再说这块了,大家都知道。
2.如何编写程序
此项目必须要有也只能有一个main()函数,如果读者的代码量很大,可以将main()里的代码分成几个小块,然后分属于不同的函数,不过这些函数要在main()前面声明一下。
3.应用场合
Win32控制台程序适用于刚接触VS的读者用来练手,或者是那些需要测试完善的代码,以便移植到其他框架下使用。

三、MFC应用程序(MFC Application)
如果读者想做界面并且不想自己从头开发的话,第一个接触的就是MFC应用程序。MFC应用程序的入口函数也是WinMain(),虽然大家在工作区的文件中看不到WinMain(),但WinMain()是真实存在的。大家可以设置断点找到WinMain()。
1.创建项目
新建一个MFC Application项目,打开VS,选择“文件一新建→项目...”命令,左上角“项目类型”选择Visual C++的MFC,其对应的模板选择"MFC应用程序”。左下方的名称可以自己决定,如取名为"MFC_Application”,存储位置也是随便定,也可以单击“浏览”按钮选择。最后单击“确定”按钮之后出现MFC应用程序向导,单击对话框左侧的“应用程序类型”选项,在“应用程序类型”选项区域中选择“单文档”。“MFC使用”等选项都默认,再点完成按钮。
这里需要重点介绍的是“MFC使用”的两种情况:
(1)在共享DLL中使用MFC:当项目进行到后期要做个.exe 的可执行文件,此时 MFC的一些DLL并没有被包含在.exe 文件中,而运行时会用到这些文件。因此当用户的计算机上没有安装相应的开发环境时就会出现“无法启动程序….,由于应用程序配置不正确,未能启动此应用程序”这样的错误。
(2)在静态库中使用MFC:在生成.exe 文件时就将DLL中的相关代码写入了.exe文件,所以在没有安装开发环境的计算机上也可以运行,缺点是这样的.exe 文件大小比“在共享DLL中使用MFC”大。
此时就创建好了一个MFC应用程序,在不添加任何代码时,这样一个MFC单文档程序就能运行生产一个窗口,窗口中会有左上角图标、标题、菜单、工具栏、状态栏,都是默认情况下的运行结果。可以根据公司的需求或个人喜好修改出更漂亮的界面。
2.如何编写程序
这个项目虽然也有入口函数,但它不需要大家去修改,而只需在适当的函数中添加自己代码或修改原有的代码即可。下面举两个例子简单介绍用何种函数具体写什么去修改界面中的何处。
(1)修改菜单、工具栏和状态栏
函数:
int OnCreate (LPCREATESTRUCT lpCreateStruct);
所在文件:MainFrm.cpp
代码类型:参看文件中原始代码,并找MSDN寻求帮助。
(2)修改界面中的空白区
函数:
void OnDraw(CDC* pDC):
所在文件:MFC_ApplicationView.cpp
代码类型:贴图、输出文字等代码。
3.应用场合
 以MFC应用程序为基本框架继续开发自己的软件,可以省去程序员一大部分工作内容。

四、创建MFC动态链接库(MFC DLL)
MFC DLL是针对MFC应用程序的动态链接库,它的入口函数是DllMain()。DllMain()就类似于MFC应用程序中的WinMain(),在自动生成的文件也是看不到的,必须追踪到内部文件,因此也不必去重新编辑这个函数。要做的就是找到接口函数写入相应的代码即可,下面简单介绍 MFC DLL如何创建、怎样编写及它的应用场合。
1.创建项目
新建一个名为MFC DLL的MFC DLL项目,打开VS开发环境,选择“文件→新建→项目..”命令,出现新建项目对话框。左上角“项目类型:”选择Visual C++的MFC,其对应的模板选择"MFC DLL"。左下方的名称可以自己决定,本项目取名为"MFC DII”,存储位置也是随便定,读者也可以单击“浏览”按钮选择。最后单击“确定”按钮之后出现MFC动态链接库向导,单击对话框左侧的“应用程序设置”选项,在选项“DLL类型”中选择“使用共享MFC DLL的规则DLL”单选按钮。其他的都保持默认状态,弄好后单击右下方的“完成”按钮。
这种项目运行结果是没有窗口的,因为它生成的并不是可执行文件,而是以.dll、.lib为后缀名的两上文件。如果想看结果,只需要将其复制粘贴到可执行程序的当前路径下,并且让可执行程序调用其结果即可。
2.如何编写程序
它的操作与MFC应用程序相似。
3.应用场合
当所编写的程序不希望被权限之外的人看到源代码,以期保护原作者的权益,或者代码被封装成接口让别人使用,这样即使不懂源代码原理的读者也可以凭借知道的输入与输出参数运用它。

各位小伙伴,这次我们就说到这里,我感觉我写的还是不够简单易懂,等我重新想一下,看看有没有什么其他写法能让大家再好懂一些。下次我们再深入研究windows MFC,相信你一定能喜欢上windows MFC。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

帮你快速理解什么是MFC(Windows环境下) 的相关文章

随机推荐

  • RabbitMQ 与 Kafka 对比

    作为一个有丰富经验的微服务系统架构师 经常有人问我 应该选择RabbitMQ还是Kafka 基于某些原因 许多开发者会把这两种技术当做等价的来看待 的确 在一些案例场景下选择RabbitMQ还是Kafka没什么差别 但是这两种技术在底层实现
  • 【jackson】自定义字段注解完成序列化逻辑

    目录 背景 本文开发环境介绍 新建一个注解 新建一个JavaBean 新建一个JsonSerializer 新建一个AnnotationIntrospector 单元测试 总结 背景 Spring默认的JSON序列化工具使用的是jackso
  • 基于CNN-LSTM数据分类:Matlab实现

    基于CNN LSTM数据分类 Matlab实现 在当今的信息时代 数据处理和分类已经成为了不可或缺的技能和工具 其中卷积神经网络 Convolutional Neural Network CNN 和长短时记忆网络 Long Short Te
  • 多少存款才是裸辞的最好姿态?

    朋友小惠上个月裸辞了 前几天见她还意气风发 没想到昨晚就和我说 焦虑来得远比想象中快 她的计划是三个月内找到满意的新工作 满打满算攒了三个月的生活费才踏出裸辞这一步 结果面试了几个公司后 对于能否在三个月内找到满意工作感到极度地焦虑 小惠认
  • [SWPUCTF 2021 新生赛]finalrce

  • tplink 703n lede -17.01 编译过程

    tplink 703n lede 17 01 编译过程 tplink 703n lede 17 01 编译过程 tplink 703n 支持USB扩展 利用其功能可实现挂载硬盘 打印机共享等 网上虽然有些现成的固件 但基于openwrt 1
  • shiro(java安全框架)

    以下都是综合之前的人加上自己的一些小总结 Apache Shiro是一个强大且易用的Java安全框架 执行身份验证 授权 密码学和会话管理 使用Shiro的易于理解的API 您可以快速 轻松地获得任何应用程序 从最小的移动应用程序到最大的网
  • SQL - MySQL回表

    一 回表概念 现象 回表 顾名思义就是回到表中 也就是先通过普通索引 我们自己建的索引不管是单列索引还是联合索引 都称为普通索引 扫描出数据所在的行 再通过行主键ID 取出索引中未包含的数据 所以回表的产生也是需要一定条件的 如果一次索引查
  • 怎么用计算机算ess tss,"ESS、RSS、TSS"分别表示什么?

    回归平方和 ESS 残差平方和 RSS 总体平方和 TSS 1 回归平方和 是反映自变量与因变量之间的相关程度的偏差平方和 用回归方程或回归线来描述变量之间的统计关系时 实验值yi与按回归线预测的值Yi并不一定完全一致 2 残差平方和是在线
  • 通过Android Studio 将yolov5部署到手机端(2023新手最新适用版)

    通过Android Studio 将yolov5部署到手机端 2023新手最新适用版 java17安装 下载java17 Java Downloads Oracle 配置环境变量 这个是我安装后的路径 将这个路径复制 设置环境变量 在系统变
  • Qt技巧:QProcess与外部程序的调用

    项目做到一定阶段 常常须要在原来的project上调用外部程序 Qt为此提供了QProcess类 QProcess可用于完毕启动外部程序 并与之交互通信 一 启动外部程序的两种方式 1 一体式 void QProcess start con
  • NFS服务安装配置(centos7 nfs-utils示例)

    测试机器 nps server 10 166 205 104 nfs client 10 166 205 101 server端 安装nfs utils和rpcbind sudo yum install nfs utils rpcbind
  • np.random里让你迷糊的随机数函数到底咋区分(结合tensorflow)

    小测 numpy以下哪个函数不能产生正态分布的随机数 A standard normal B randn C random D normal 从 0 1 范围的标准分布中产生1个随机数 以下哪个numpy函数是错误的 A rand B ra
  • Sort 【HDU - 5884】【哈夫曼树】

    题目链接 一开始看到题的时候 竟然读成了是按照升序排序的一串数 害得我WA了两发 还以为是补0补错了 研究了一会补0发现好像没有多大问题 然后就继续了 直到再看了遍题 发现好像是没有给你拍好序的 然后AC 这道题其实哈夫曼树不难 就是补0思
  • 【信创】麒麟操作系统配置在线源及手动查找所需软件包

    获取操作系统信息 命令 nkvers 关注倒数第2行 示例中大版本 V10 小版本 SP2 CPU架构 aarch64 root localhost nkvers Kylin Linux Version Release Kylin Linu
  • ThreadLocal原理以及其安全问题

    ThreadLocal 是一个线程内共享数据的类 其原理是在线程有一个 ThreadLocalMap key是ThreadLocal对象 value是自定义的数据 所以在同一个线程中 用同一个threadlocal去get数据 能取到同样的
  • ansible 离线部署

    1 安装 python 环境 wget https mirrors bfsu edu cn anaconda archive Anaconda3 2022 10 Linux x86 64 sh sh Anaconda3 2022 10 Li
  • VUE+echart绘制地图(伪3D)

    这里以宝鸡地图为示例 其他地图只需更换地图JSON 地图JSON获取通过阿里的datav 地址 阿里云地图获取工具 和data数值即可 效果图如下 首先我们需要创建一个div来盛放地图 这里的div必须给出对应的宽和高 不然地图无法显示 t
  • JavaSE核心API

    还在更新中 没有JavaSE基础的小伙伴可以先看看这篇哦 写的非常的详细 Java语言基础 文章目录 API介绍以及文档的使用 文档注释的规范 Javadoc生成项目文档 String的介绍 重写equals方法 字符串常量池 String
  • 帮你快速理解什么是MFC(Windows环境下)

    我是荔园微风 作为一名在IT界整整25年的老兵 今天总结一下Windows环境下的MFC到底是一个什么技术 早在1998年 MFC绝对是技术界的一个热门名词 现在似乎提的人很少 但其他MFC的很多程序仍在世界上各个角落运行着 做为一名系统架