Visual Studio 2022的MFC框架——AfxWinMain全局对象和InitInstance函数

news2024/12/23 5:03:20

我是荔园微风,作为一名在IT界整整25年的老兵,今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。 

在看这篇帖子前,请先看我的另一篇帖子《Visual Studio 2022的MFC框架——应用程序向导》。

当程序调用了CWinApp类的构造函数,并执行了CMfcApp类的构造函数,且产生了theApp 对象之后,接下来就进入 WinMain 函数。根据前面我写的一些MFC帖子所示的代码,可以发现WinMain 函数实际上是通过调用 AfxWinMain函数来完成它的功能的。

Afx前缀的函数代表应用程序框架Application Framework函数。应用程序框架实际上是一套辅助我们生成应用程序的框架模型。该模型把多个类进行了一个有机的集成,可以根据该模型提供的方案来设计我们自己的应用程序。在MFC中,以Afx为前缀的函数都是全局函数,可以在程序的任何地方调用它们。

我们可以采取同样的方式查找定义AfxWinMain 函数的源文件,在搜索到的文件中双击winmain.cpp,并在其中找到 AfxWinMain函数的定义代码。

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\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\n", 
       AfxGetModuleThreadState ()->m_nTempMapLock);
      }
     AfxLockTempMaps ();
     AfxUnlockTempMaps (-1);
  #endif

  AfxWinTerm();
  return nReturnCode;
  }

在上面所示的代码中,AfxWinMain首先调用AfxGetThread函数获得一个CWinThread类型的指针,接着调用 AfxGetApp函数获得一个CWinApp类型的指针。从MFC类库组织结构图中可以知道CWinApp派生于CWinThread。

下面是AfxGetThread函数的源代码,位于thrdcore.cpp文件中。

CWinThread* AFXAPI AfxGetThread()
{
  // check for current thread in module thread state

   AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState ();
   CWinThread* pThread = pState->m_pCurrentWinThread;
  return pThread;
}

从上面所示代码中可以发现, AfxGetThread函数返回的就是在 CWinApp构造函数中保存的 this指针。对Mfc程序来说,这个this指针实际上指向的是CMfcApp的全局对象:theApp。

AfxGetApp是一个全局函数,定义于 afxwin1.inl中:

_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()

   { return afxCurrentWinApp;}

而afxCurrentWinApp的定义位于 afxwin.h文件中,代码如下:

#define afxCurrentWinApp    AfxGetModuleState()->m_pCurrentWinApp

结合查看之前关于MFC帖子中所示的CWinApp构造函数代码,就可以知道 AfxGetApp函数返回的是在 CWinApp 构造函数中保存的 this 指针。对Mfc程序来说, 这个 this 指针实际上指向的是 CMfcApp的对象: theApp。也就是说,对Mfc程序来说, pThread和 pApp所指向的都是CMfcApp类的对象,即theApp全对象。

再来说说InitInstance函数,再回到上面所示的 AfxWinMain函数,可以看到在接下来的代码中,pThread和 pApp调用了三个函数,这三个函数就完成了Win32程序所需要的几个步骤:设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环,以及窗口过程函数。pApp首先调用 InitApplication函数,该函数完成MFC内部管理方面的工作。

接着,调用pThread的 InitInstance 函数。在Mfc程序中,可以发现从 CWinApp派生的应用程序类CMfcApp也有一个InitInstance函数,其声明代码如下所示。

virtual BOOL InitInstance();

从其定义可以知道,InitInstance函数是一个虚函数。根据类的多态性原理,可以知道AfxWinMain函数在这里调用的实际上是子类  CMfcApp 的 InitInstance函数。CMfcApp类的 InitInstance函数定义代码如下所示。

BOOL CMfcApp::InitInstance()
{
  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);

  SetRegistryKey(_T("应用程序向导生成的本地应用程序")
    LoadStdProfileSettings(4); //加载标准 INI 文件选项(包括 MRU)

    //注册应用程序的文档模板。  文档模板
  //将用作文档、框架窗口和视图之间的连接

  CSingleDocTemplate* pDocTemplate;

  pDocTemplate = new CSingleDocTemplate(
  IDR_MAINFRAME,
    RUNTIME_CLASS (CMfcDoc),
    RUNTIME_CLASS (CMainFrame),  //主SDI框架窗口
    RUNTIME_CLASS (CMfcView));
  if ( !pDocTemplate)
     return FALSE;
  AddDocTemplate (pDocTemplate);

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

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

这几篇内容涉及的内容有点难,如果大家看不懂,要结合其他VC的资料综合看。

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

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

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

相关文章

shell常用脚本

1、Java项目重启脚本 #!/bin/bash# 定义一个函数来结束进程和启动新进程 function restart(){JAR_NAME$1 # jar包LOG_NAME$2 # 日志JVM_ARGS$3 # jvm 参数PID$(ps -ef | grep java | grep ${JAR_NAME} | awk { print $2 })if [[ ! -z "$PID" ]]; thenecho "…

LeetCode(力扣)700. 二叉搜索树中的搜索Python

LeetCode20. 有效的括号 题目链接代码 题目链接 https://leetcode.cn/problems/search-in-a-binary-search-tree/ 代码 递归法 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val #…

进度猫:如何做好项目进度管理?有几点建议

项目目进度管理是在项目实施过程中,对各阶段的进展和项目最终完成的期限进行的管理。目的是保证项目能在满足其时间的约束条件的前提下实现项目的总体目标。 因此为了保证项目能够按时完成,需要制订详尽的可操作性的项目进度管理计划,才可以…

MySQL数据库备份及恢复

数据备份的重要性 1、备份的主要目的是灾难恢复 2、在生产环境中,数据的安全性至关重要 3、任何数据的丢失都可能产生严重的后果 4、造成数据丢失的原因 备份类型(重点) 1、物理备份 数据库备份可以分为物理备份和逻辑备份。物理备份是对数据库操作系统的物…

【App端】uni-app使用百度地图api和echarts省市地图下钻

目录 前言方案一:echarts百度地图获取百度地图AK安装echarts和引入百度地图api完整使用代码 方案二:echarts地图和柱状图变形动画实现思路完整使用代码 方案三:中国地图和各省市地图下钻实现思路完整使用代码 前言 近期的app项目中想加一个功…

QGIS-计算几何内部点(一定在几何内)

在提取几何图像的中心点相关的X Y时,我们往往希望提取的点在几何内部,因为对于不规则图形而言,特别是凹几何,提取的点可能在图形外,QGIS中提供了相关的函数用于提取点中心点: 打开图形的属性列表&#xff…

Springboot2.0 上传图片 jar包导出启动(第二章)

目录 一,目录文件结构讲解二,文件上传实战三,jar包方式运行web项目的文件上传和访问处理(核心知识)最后 一,目录文件结构讲解 简介:讲解SpringBoot目录文件结构和官方推荐的目录规范 1、目录讲解…

行业毒瘤还是长久需求?无代码编程会是趋势吗?

无代码和低代码都是这几年才诞生、但受到不少关注的新名词。无代码和低代码的发展前景如何?是一时兴起还是长久需求,是不是行业毒瘤,种种讨论络绎不绝。 无代码开发平台(NCDP,No Code Development Platform&#xff09…

Java从入门到精通(五)· 内部类,枚举,泛型

Java从入门到精通(五) 内部类,枚举,泛型 一 内部类 1.概述 简单来说,如果一个类定义在另一个类的内部,这个类就是内部类。 使用场景:当一个类的内部,包含了一个完整的事务&#…

常见的软件测试模型

目录 1、瀑布模型 2、V模型 3、W模型 4、H模型 5、X模型 1、瀑布模型 瀑布模型是一种线性的、顺序的软件开发模型 上一阶段的输出结果作为下一阶段的输入 优点: (1)为项目提供了按阶段划分的检查点。 (2)当前一阶段…

【校招VIP】产品面试之面试官的真实意图

考点介绍: 大厂面试时,面试官提出的问题除了了解经历和想法外,最看重的是思维逻辑能力、团队协作能力和协调能力。 『产品面试之面试官的真实意图』相关题目及解析内容可点击文章末尾链接查看! 一、考点题目 1. 你遇到的最大的…

QT 相关设置

目录 1.安装QT2.安装好之后需要做一些设置2.1 基本的字体及主题设置2.2 格式化美化代码插件设置 1.安装QT 具体教程不写了 2.安装好之后需要做一些设置 2.1 基本的字体及主题设置 进入选项 选择喜欢的主题 字号字体设置 2.2 格式化美化代码插件设置 先下载一个格式化插…

五、多表查询-4.6练习

一、准备数据 【效果展示】 emp1表(员工表): dept1表(部门表): salgrade表(薪资等级表): 二、案例 1、查询员工的姓名、年龄、职位、部门信息(隐式内连接&am…

JUC详解

👏作者简介:大家好,我是爱发博客的嗯哼,爱好Java的小菜鸟 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦 📝社区论坛:希望大家能加入社区共同进步…

leetcode 823. 带因子的二叉树(dp+双指针+Long类型)

leetcode 823. 带因子的二叉树(dp双指针Long类型) 题目表述 给出一个含有不重复整数元素的数组 arr ,每个整数 arr[i] 均大于 1。 用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积…

个人博客论坛系统测试报告

目录 一、项目介绍 二、测试计划 1、功能测试 (1)测试环境: (2)测试用例编写 (3)部分功能测试 2、自动化测试 🍑注册页面测试 验证注册成功的情况 验证注册失败的情况 &a…

WebDAV之π-Disk派盘 + 思源笔记

思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。 融合块、大纲和双向链接,重构你的思维。 π-Disk派盘 – 知识管理专家 派盘是一款面向个人和企业的本地云存储解决方案,它可以帮助用户打造“数字第二大脑”,并支持KMS知识管理系…

Qt自定义标题栏

一、创建项目 最终项目文件结构如下 “iconfont.tff”的使用方式见如下博客,用于更改图标颜色Qt更改图标颜色_怎么追摩羯座的博客-CSDN博客 二、MyTitleBar.pro #------------------------------------------------- # # Project created by QtCreator 2023-08-2…

antd upload组件beforeUpload返回promise之后,获取的文件不是file类型导致上传失败

之前的beforeUpload直接返回一个false值 ,文件是可以正常与服务端进行传输的 beforeUpload: (file) > {return false},但是这样并不能阻止文件上传,看了官方文档后,改用返回promise对象上传 beforeUpload: (file) > {console.log(-befo…

Primeng table filter 重置条件

我用一个overlayPanel装了p-table,里面有个count的filter,但是我设置值之后,让overlayPanel消失,再出现的时候,明明已经重新设置了表里面的数据和filter的变量值,但是上一次的条件仍然在,旁边的文字filter依…