VC++编程:MFC程序中的WinMain入口函数

2023-11-22 22:58

本文主要是介绍VC++编程:MFC程序中的WinMain入口函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


     程序之家转载文章:
     读者还记得我们在第2章中讲述的创建Win32应用程序的几个步骤吗?当时,我们介绍Win32应用程序有一条很明确的主线:首先进入WinMain函数,然后设计窗口类、注册窗口类、产生窗口、注册窗口、显示窗口、更新窗口,最后进入消息循环,将消息
路由到窗口过程函数中去处理。遵循这条主线,我们在写程序时就有了一条很清晰的脉络。


  但在编写MFC程序时,我们找不到这样一条主线,甚至在程序中找不到WinMain函数。可以在当前Test工程中查找WinMain函数,方法是在VC++开发环境中单击【Edit】菜单,选择【Find in Files…】菜单项,并在弹出的查找对话框中“Find What:”文本框内输入“WinMain”,单击【Find】按钮,结果当然是找不到WinMain函数。读者可以在这个工程中,再查找一下WNDCLASS、CreateWindow等,你会发现仍然找不到。那么是不是MFC程序就不需要WinMain函数,不需要设计窗口类,不需要创建窗口了呢?当然不是。我们之所以看不见这些,是因为微软在MFC的底层框架类中封装了这些每一个窗口应用程序都需要的步骤,目的主要是为了简化程序员的开发工作,但这也给我们在学习和掌握MFC程序时造成了很多不必要的困扰。


  为了更好地学习和掌握基于MFC的程序,有必要对MFC的运行机制,以及封装原理有所了解。在第1章就讲述了WinMain函数是所有Win32程序的入口函数,就像DOS下的main函数一样。我们创建的这个MFC程序也不例外,它也有一个WinMain函数,但这个WinMain函数是在程序编译链接时,由链接器将该函数链接到Test程序中的。


  在安装完Microsoft Visual Studio 6.0后,在安装目录下(将Microsoft Visual Studio 6.0安装到了D:\Program Files下),微软提供了部分MFC的源代码,我们可以跟踪这些源代码,来找出程序运行的脉络。机器上MFC源代码的具体路径为D:\Program Files\Microsoft Visual Studio\VC98\MFC\ SRC,读者可以根据这个目录结构在自己机器上查找相应的目录。找到相应的目录后,在资源浏览器的工具栏上选择“搜索”。然后在搜索窗口的“包含文字”文本框中输入”WinMain”,单击“立即搜索(S)”按钮,搜索结果如图3.12所示。




图片



图3.12 包含“WinMain”文字的搜索结果


我们只需要查看后缀名为CPP的源文件即可,实际上,WinMain函数在APPMODUL.CPP这个文件中。保持Test工程的打开状态,然后双击APPMODUL.CPP即可在VC++环境中打开该文件,在其中可以找到如例3-1所示的这段代码。


  例3-1
  extern "C" int WINAPI
  _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPTSTR lpCmdLine, int nCmdShow)
  {
  // call shared/exported WinMain
  return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
  }


  WinMain函数找到了。现在我们可以看看Test程序是否会进入这个WinMain函数。在WinMain函数中按下F9键设置一个断点,然后按下F5键调试运行当前程序。我们发现程序确实运行到该断点处停了下来,如图3.13所示。这说明Test这个MFC程序确实有WinMain函数,在程序编译链接时,WinMain函数就成为该程序的一部分。



图片
图3.13 程序运行到WinMain断点处


  但这个_tWinMain函数和第1章所讲的WinMain函数有些不同,让我们先看看这个函数的定义。读者可以在_tWinMain上单击鼠标右键,从弹出的快捷菜单中选择【Go To Definition Of _tWinMain】菜单项,光标就会定位到_tWinMain函数的定义处,代码如例3-2所示,从中我们可以发现_tWinMain实际上是一个宏,展开之后就是WinMain函数。




例3-2
  #define _tmain main
  #define _tWinMain WinMain
  #ifdef _POSIX_
  #define _tenviron environ
  #else
  #define _tenviron _environ
  #endif
  #define __targv __argv


  1.theApp全局对象


  找到了WinMain函数,那么它是如何与MFC程序中的各个类组织在一起的呢?也就是说,MFC程序中的类是如何与WinMain函数关联起来的呢?


  双击ClassView标签页中的CTestApp类,跳转到该类的定义文件(Test.h)中。可以发现CTestApp派生于CWinApp类,后者表示应用程序类。我们在ClassView标签页中打开CTestApp类前面的“+”符号,双击该类的构造函数,就跳转到该类的源文件(Test.cpp)中。在CTestApp构造函数处设置一个断点,然后调试运行Test程序,将发现程序首先停在CTestApp类的构造函数处,继续运行该程序。这时程序才进入WinMain函数,即停在先前我们在WinMain函数中设置的断点处。


  在我们通常的理解当中,WinMain函数是程序的入口函数。也就是说,程序运行时首先应该调用的是WinMain函数,那么这里为什么程序会首先调用CTestApp类的构造函数呢?看一下CTestApp的源文件,可以发现程序中定义了一个CTestApp类型的全局对象:theApp。代码如下。


  // The one and only CTestApp object
  CTestApp theApp;


  提示:MFC程序的全局变量都放置在ClassView标签页的Globals分支下,展开该分支即可看到程序当前所有的全局变量。双击某个全局变量,即可定位到该变量的定义处。


  我们在这个全局对象定义处设置一个断点,然后调试运行Test程序,将发现程序执行的顺序依次是:theApp全局对象定义处、TestApp构造函数,然后才是WinMain函数。


  为了更好地解释这一过程,我们再新创建一个Win32控制台工程。单击【File】菜单,选择【New】菜单项, 在Projects选项卡下,选择Win32 Console Application类型,在右侧的Project name文本框中输入工程名:main,并将程序放置到适当的位置(即设置Location的内容),如图3.14所示。


图片
图3.14 新建Win32控制台应用

  单击【OK】按钮,进入“Win32 Console Application”向导,选择一个空工程即可,如图3.15所示。单击【Finish】按钮,向导就自动生成一个空的Win32控制台应用框架。


  接着为这个main工程新建一个源文件,方法是单击【File】菜单,选择【New】命令,在弹出的【New】对话框中选择【Files】选项卡,然后选择C++ Source File项,并在右侧的【File】文本框中输入源文件名:main,如图3.16所示。



图片
图3.15 Win32 Console Application向导



图片
图3.16 新建一个源文件



接下来,在main.cpp文件中输入如例3-3所示的代码。

  例3-3
  #include
  int a=6;
  void main()
  {
  cout<
  }


  上述代码非常简单,首先定义了一个int类型的全局变量a,并给它赋了一个初值6。然后定义了一个main函数,该函数所做的工作就是将全局变量a的值输出到标准输出cout上。因为使用了标准输出,所以需要包含相应的头文件:iostream.h,这是C++中的标准输入输出流头文件。


  我们在main函数处设置一个断点,调试运行该程序,将会发现程序在进入main函数时,a的值已经是6了。也就是说,在程序入口main函数加载时,系统就已经为全局变量或全局对象分配了存储空间,并为它们赋了初始值。


  小技巧:在程序运行过程中,如果想要查看某个变量的当前值,方法一是把鼠标移到该变量上,停留片刻,VC++就会弹出一个小窗口,此窗口中显示了该变量的当前值,如图3.17所示。



图片
图3.17 显示当前变量取值的小窗口


  方法二是利用VC++提供的调试窗口来查看变量的当前值。操作步骤是单击View菜单,选择Debug Windows选项,在下拉菜单中选择Variables菜单项,即可显示变量窗口,如图3.18所示。该窗口显示了程序当前上下文中的一些重要变量的当前值。



图片
图3.18 Variables窗口


这篇关于VC++编程:MFC程序中的WinMain入口函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/413512

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)