【MFC】初识MFC(8)

news2025/8/11 14:08:37

MFC简介

微软提供的一个类库(Class Libraries),封装了Windows的API,并且包含一个应用程序框架。

1、MFC是对前面窗口编程所用到的API进行封装,在Windows C基础上引入了C++面向对象的思想,简单而言就是把API函数和处理数据捆绑一起,做成了类——当然封装、继承、多态的机制也应用起来;

2、MFC不仅仅是类库(类的一个集合),而且还是一个应用程序框架——已经搭建好了程序的“骨架”(毛坯房),程序员只需要”修修改改“,实现实际功能即可。

理解:

1、Windows C 当然需要掌握,MFC把API进行了一层简单的包装,函数名称、功能、调用的方法大体相同——所以学MFC,必先了解SDK编程;

2、框架的意义在于,不是让程序员自主地调用MFC里的类,而是以框架为基础,被动地接受这种开发的模式——降低”编码“的难度?包括了两(三)种应用程序开发模式:

  • 单文档、多文档:应用程序(实现程序初始化)、框架(管理程序的各个窗口)、视图(用户区和数据展示窗口、一个程序可以有多个)、文档(程序的数据)的窗口程序模式——单文档、多文档应用程序。
  •   对话框:简化单文档、多文档中框架和文档,集中于窗口元素(按钮、文本框、编辑框、列表等等)的可视化设计模式。

 初衷是,MFC告诉你写代码的地方(类向导里的消息响应),你去实现自己的功能吧,就这么简单!

后果是,初学者看到这些”自动“生成代码,被”框架“ 搞得不知所措,战战兢兢,不敢下手。也就是照葫芦画瓢,照写几个范例而已。

因此,了解MFC的实现机制,MFC与SDK编程的关系,掌握这个只能被接受的框架,才能打开程序员设计的思路,放开手脚,自由地实现自己的功能。(推荐书:《深入浅出MFC》)

MFC机制

窗口编程 WinMain 函数是少不了,编译型的程序,入口总是避免不了。创建MFC程序(单文档、多文档、对话框)后在工程中并没发现WinMain函数,程序流程就搞不清楚了。

MFC在程序编译时自动补上WinMain函数,函数的实现在VS的安装目录,比如

C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\src\mfc    (VS2012)

 代码是这样的:

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "sal.h"


/
// Standard WinMain implementation
//  Can be replaced as long as 'AfxWinInit' is called first

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	_In_ LPTSTR lpCmdLine, int nCmdShow)
{
	ASSERT(hPrevInstance == NULL);

	int nReturnCode = -1;
	CWinThread* pThread = AfxGetThread();
	CWinApp* pApp = AfxGetApp();

	// AFX internal initialization
	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
		goto InitFailure;

	// App global initializations (rare)
	if (pApp != NULL && !pApp->InitApplication())
		goto InitFailure;

	// Perform specific initializations
	if (!pThread->InitInstance())
	{
		if (pThread->m_pMainWnd != NULL)
		{
			TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
			pThread->m_pMainWnd->DestroyWindow();
		}
		nReturnCode = pThread->ExitInstance();
		goto InitFailure;
	}
	nReturnCode = pThread->Run();

InitFailure:
#ifdef _DEBUG
	// Check for missing AfxLockTempMap calls
	if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
	{
		TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
			AfxGetModuleThreadState()->m_nTempMapLock);
	}
	AfxLockTempMaps();
	AfxUnlockTempMaps(-1);
#endif

	AfxWinTerm();
	return nReturnCode;
}

/

AfxWinMain 就是WinMain函数(F12可以看定义,_tWinMain等等可以忽略),可能是为了避免MFC ”非纯面向对象“ 程序设计框架(纯面向对象语言是没用全局变量、全局函数),隐藏主函数也是一种办法吧!

开始入口:

   CWinThread* pThread = AfxGetThread();
   CWinApp* pApp = AfxGetApp();

CWinThread  是  CWinApp 的父类,可以暂时不关心。

CWinApp  其实是创建MFC框架时,应用程序类的父类:

并且,在应用程序的源文件中,可以找到一个全局对象的定义:

  AfxGetApp() 的函数功能可以猜到了吧,父类的指针 指向 派生类的 对象!

多态的思想,这时候父类指针调用的函数 就 ”自动地切换“ 到程序员写的代码里去了。

否则,MFC这么知道程序员定义了一个什么类?怎么去调用这个类定义的函数作为程序的切入点?

AfxWinInit 函数在同层目录下的appinit.cpp文件里,这个函数的功能可以忽略。

下面就是InitApplication,派生类没有改写,调用  CWinApp 类(同层目录appcore.cpp),这个可以忽略。

重点当然是 InitInstance,这个函数在派生类中进行了改写,那么转入派生类应用程序类中的函数调用:(以单文档为例,其他都类似)

BOOL CMFC01App::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	// 初始化 OLE 库
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();

	EnableTaskbarInteraction(FALSE);

	// 使用 RichEdit 控件需要  AfxInitRichEdit2()	
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)


	// 注册应用程序的文档模板。文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CMFC01Doc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CMFC01View));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);


	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);



	// 调度在命令行中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}

比较重要的是所谓的”三口组“,CSingleDocTemplate(单文档模板)捆绑框架、视图、数据,一起生成对象。这里面当然最核心的问题就是:窗户函数,涉及到消息的处理,这也是程序员非常需要关注的。

要找窗口函数,肯定要找窗口类的注册,查找的过程可以参考《深入浅出MFC》,结论是:从WINFRM.CPP 文件的Create 到  WINCORE.CPP 里的 CreateEx函数:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName, DWORD dwStyle,
	int x, int y, int nWidth, int nHeight,
	HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
	ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) || 
		AfxIsValidAtom(lpszClassName));
	ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
	
	// allow modification of several common create parameters
	CREATESTRUCT cs;
	cs.dwExStyle = dwExStyle;
	cs.lpszClass = lpszClassName;
	cs.lpszName = lpszWindowName;
	cs.style = dwStyle;
	cs.x = x;
	cs.y = y;
	cs.cx = nWidth;
	cs.cy = nHeight;
	cs.hwndParent = hWndParent;
	cs.hMenu = nIDorHMenu;
	cs.hInstance = AfxGetInstanceHandle();
	cs.lpCreateParams = lpParam;

	if (!PreCreateWindow(cs))
	{
		PostNcDestroy();
		return FALSE;
	}

	AfxHookWindowCreate(this);
	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);

#ifdef _DEBUG
	if (hWnd == NULL)
	{
		TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
			GetLastError());
	}
#endif

	if (!AfxUnhookWindowCreate())
		PostNcDestroy();        // cleanup if CreateWindowEx fails too soon

	if (hWnd == NULL)
		return FALSE;
	ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
	return TRUE;
}

然后又转回WINFRM.CPP 等等,这个过程对初学者而言可以忽略,核心问题是了解MFC的程序流程。

wndcls.lpfnWndProc = DefWindowProc;  这就是答案。

后续《深入浅出MFC》中很大篇幅来讲解MFC的消息处理机制(三种类型消息),这个也暂时可以忽略。类向导-》消息响应、虚函数的使用就比较清晰了:

 可以不问来由,只管使用了,希望简单点,直接响应!否则改写DefWindowProc函数抓取所有窗口消息,也非常的灵活淡定!

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

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

相关文章

【论文翻译】2.5PC:一个更快的非阻塞原子提交协议

2.5-PC: A Faster and Non-Blocking Atomic Commit Protocol 目录1 介绍2 相关工作3 原子承诺和 3PC 概述4 为什么 3PC 是非阻塞的?5 2.5 PC6 2.5 PC 的非正式证明7 确认信息8 2.5 PC 机器证明参考摘要:我们提出 2.5PC,一种非阻塞原子提交协…

DNS与网站访问流程

1:dns与网址url简介 DNS是域名系统(DomainNameSystem)的缩写,域名系统是一中庞大而复杂的系统,但我们这里讲解重心并不是这个系统,而是指本地电脑dns是什么 讲到dns,我们就不得不讲讲网址和域名,我们经常会…

linux杀死进程的五种方法(kill)

添加链接描述 相关博主的链接; 方法一:通过kill 进程id的方式可以实现 首先需要知道进程id, 例如,想要杀死firefox的进程,通过 ps -ef|grep firefox,可以查到firefox的进程id: 然后通过 kill 3781 就可以关闭进程了. 补充: kill -9 来强制终止退出, 例…

16.一篇文章学会django模型的使用

1.django模型简单示例 1.1 创建django项目 创建完项目,还需要创建django子项目 django-admin startproject model_study cd .\model_study\ python manage.py startapp model_app1.2配置应用 将模型对应的应用程序(刚刚创建的子应用)添加…

CentOS 7 Jenkins配置及SpringBoot项目自动部署

1.下载Jenkins 下载地址:War Jenkins Packages 运行Jenkins之前确保系统已经安装好JDK,因为我安装的是JDK1.8,所以选择2.346.1 这个版本 2.启动jenkins 将下载好的jenkins.war上传到服务器上,我的目录是/home/jenkins 启动命令 java -jar jenkins.war --httpPo…

万字详文:TCP 拥塞控制详解

本文主要介绍 TCP 拥塞控制算法,内容多来自网上各个大佬的博客及《TCP/IP 详解》一书,在此基础上进行梳理总结,与大家分享。因水平有限,内容多有不足之处, 敬请谅解。一、TCP 首部格式 在了解 TCP 的拥塞控制之前&…

多向思考者--高敏感人群的内心世界

工作以后很少看心理学的书,因为心理学书给我的印象是:国外翻译的很啰嗦,国内的太鸡汤,看的时候能有感触,看完以后就都忘记了。阅读心理学的书籍,更多的是跟着书中的内容和自己对话。看完《多向思考者》这本…

SpringMVC使用(二)

1. 统一异常处理 SpringMVC提供了统一处理Controller层抛出的异常的方法 1.1 统一异常处理案例 RestController的统一异常处理 package com.lan.controller;import com.lan.exception.BusinessException; import com.lan.exception.SystemException; import org.springfram…

DolphinDB Kafka 插件介绍

1. DolphinDB Kafka 插件介绍 DolphinDB Kafka 插件支持把 DolphinDB 中生产的数据推送到 Kafka,也支持从 Kafka 订阅数据,并在 DolphinDB 中消费。用户可以在 DolphinDB 中实例化 Producer 对象,把 DolphinDB 中的数据同步到 Kafka 中指定的…

LeetCode | 218. 天际线问题

城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回由这些建筑物形成的天际线 。 每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] [lefti, righti, heighti] 表示:…

Egg如何实现文件上传

文件上传是开发中不可避免的一项。那么在没有单独的资源服务器的时候&#xff0c;上传的文件可能要放在我们的项目文件夹服务器上&#xff0c;我们如何实现文件上传呢&#xff1f; 首先不用想&#xff0c;我们需要一个测试页面。html用来上传文件。如下&#xff1a; <!DOCT…

D. Minimal Height Tree(如何BFS遍历序列使树的高度最小)

Problem - 1437D - Codeforces Monocarp有一棵由n个顶点组成的树&#xff0c;它的根在顶点1。他决定研究BFS&#xff08;宽度优先搜索&#xff09;&#xff0c;所以他在他的树上运行BFS&#xff0c;从根开始。BFS可以用下面的伪代码来描述。 a [] # 顶点被处理的顺序 q Queu…

mdr1基因寡核苷酸/酸敏感靶多肽/聚乙二醇埃博霉素B偶联阿霉素的相关制备

小编这里整理了mdr1基因寡核苷酸/酸敏感靶多肽/聚乙二醇埃博霉素B偶联阿霉素的相关内容&#xff0c;一起来看&#xff01; 聚乙二醇埃博霉素B偶联阿霉素相关研究&#xff1a; 阿霉素与酰肼聚乙二醇羧基在磷酸的作用下反应制得阿霉素聚乙二醇羧基中间体,其中阿霉素与磷酸的摩尔比…

Android App手势冲突处理中上下左右滑动的处理以及侧滑边缘菜单的讲解及实战(附源码 可直接使用)

运行有问题或需要源码请 点赞关注收藏后评论区留言~~~ 一、上下滚动与左右滑动的冲突处理 Android控件繁多&#xff0c;允许滚动或滑动操作的视图也不少&#xff0c;如果开发者要自己接管手势处理&#xff0c;那么这个页面的滑动就存在冲突的情况&#xff0c;如果系统响应了A视…

贴花、射线、动画通知——足迹01

案例实现效果&#xff1a; 人物跑步留下脚印&#xff08;其他运动留下脚印也是同理&#xff09;。 重点&#xff1a; 贴花的创建、射线、动画通知。射线碰撞决定贴花生成位置&#xff0c;动画通知决定贴花生成时间。 一、贴花 1、贴花纹理图 在网络上找素材&#xff08…

JavaSE之动态代理

目录动态代理动态代理的好处Proxy重写invoke方法实例最后动态代理 动态代理需要确定要代理的对象&#xff0c;所以需要先new一个要代理的对象 动态代理的好处 可以在不改变方法源码的情况下&#xff0c;实现对方法功能的增强。 简化了代码。 提高了软件系统的可扩展性。 P…

【TensorRT】神经网络中的量化

文章目录一、TensorRT 为什么需要量化二、基础内容三、神经网络的量化过程一、TensorRT 为什么需要量化 量化是什么&#xff1a;量化在数字信号处理领域&#xff0c;是指将信号的连续取值&#xff08;或者大量可能的离散取值&#xff09;近似为有限多个&#xff08;或较少的&a…

七彩动态|棱镜七彩获“北京国家金融科技认证中心”颁发的「金融开源技术服务商能力评估证书」

11月13日&#xff0c;由北京金融科技产业联盟举办的第二届会员大会第四次会议在北京召开。 聚焦开源应用与安全&#xff0c;棱镜七彩通过北京国家金融科技认证中心“金融业开源评估”—金融开源技术服务商能力评估&#xff0c;并获得由北京国家金融科技认证中心颁发的“金融开…

对梯度回传的理解

参考 对梯度回传的理解 - 云社区 - 腾讯云 神经网络的每一层可以看做是使用一个函数对变量的一次计算。在微分中链式法则用于计算复合函数的导数。反向传播时一种计算链式法则的算法&#xff0c;使用高效的特定运算顺序。 设x是实数&#xff0c;f和g是从实数映射到实数的函数。…

分享一个单片机GUI库,简洁,使用

1-介绍一下 先来几张图&#xff1a; 看着是不是还不错。这个是一个国外的爱好者开发的&#xff0c;笔者有次逛网站&#xff0c;搜GUI看到的没感觉还不错&#xff0c;今天特意给大家分享一下。 这个GUI是一个用于嵌入式系统的免费开源图形库。平台独立的&#xff0c;也就是说可…