零基础学Visual C++(第4版)
上QQ阅读APP看书,第一时间看更新

第1章 Visual C++6.0开发环境和应用程序框架

在某计算机系统下编程语言,必定经过编译或解析为机器语言,才能被计算机理解并执行。高级编程语言按照翻译方式可以分为编译型和解释型两类。C++是一种编译型的高级编程语言,其过程严格按照6个步骤进行,依次为语法分析、词法分析、语义分析、中间代码生成、优化代码和目标代码生成。Visual C++6.0是当今主流的C/C++集成开发环境,除集编辑、编译和运行于一体外,还提供了丰富的控件、菜单和类定义自动处理功能。本章涉及的知识点如下。

·Visual C++6.0的安装过程和软件项目创建过程。

·Visual C++6.0简介。通过学习,读者可以熟悉Visual C++6.0的界面、各菜单项的功能,可以理解高级编程语言的编译原理过程,并学会使用帮助来解决在开发软件过程中遇到的特殊问题。

·MFC、Win32的创建。通过学习,读者可以学会MFC、Win32程序的创建、编译和执行,并可以学会使用Visual C++6.0调试器在程序运行时对变量或函数的调用顺序进行跟踪,提高程序排错效率。

·Microsoft应用程序框架。通过学习,读者可以掌握MFC应用程序框架结构和消息传递的相关知识,为学习本书第二篇和第三篇打下基础。

·实践练习。通过学习,读者可以学会创建自己的程序,并进行简单修改。

1.1 安装并测试Visual C++6.0

本节首先介绍Visual C++6.0的安装过程,然后简要介绍Visual C++6.0开发环境的相关技术背景,最后使用Visual C++6.0应用程序向导创建一个项目,以测试Visual C++6.0是否安装成功。

1.1.1 Visual C++6.0的安装

Visual C++6.0(简称VC 6.0)是美国Microsoft公司研发的基于Windows操作系统的C++集成开发环境。较早期程序设计的各个阶段都要用不同的软件来进行处理,如先用字处理软件编辑源程序,然后用链接程序进行函数、模块连接,再用编译程序进行编译,开发者必须在几种软件间来回切换操作。在这种开发条件下,软件研发是非常烦琐的,而且大多数浪费时间的烦琐手续对软件研发没有任何帮助。集成开发环境将这些烦琐工作流程集中在一个软件环境,通过这个软件环境来完成所有软件研发步骤,无须切换不同的开发工具。

高级语言编程的学习主要分为语言理论和开发工具两个方面。Visual C++6.0作为一个集成开发环境,是初学者学习的重点。本书所使用的全部实例是在Windows XP操作系统和Visual C++6.0开发环境下通过编译的,读者未必都要使用Windows XP操作系统,但安装一个Visual C++6.0是必要的。安装步骤如下。

(1)打开光盘或安装文件根目录,双击SETUP执行文件,如图1-1所示。该图显示的是存放Visual C++6.0安装文件的目录。

(2)双击SETUP执行文件后,会出现如图1-2所示的安装向导,图1-2所示界面显示的是Visual C++6.0安装欢迎信息。单击“View Readme”按钮可以阅读Visual C++6.0相关的自序文件,单击“Next”按钮即可进入下一步。

图1-1 Visual C++6.0安装程序

图1-2 Visual C++6.0安装向导——欢迎界面

(3)在条款阅读向导页面中选中“I accept the agreement”单选按钮,再单击“Next”按钮,表示用户同意Microsoft公司的安装条款,如图1-3所示。

(4)填写产品密钥安装向导页面如图1-4所示。该页面要求用户填写产品ID、姓名和工作单位等相关信息,填写完成后单击“Next”按钮进入下一步。

图1-3 Visual C++6.0安装向导——条款阅读

图1-4 Visual C++6.0安装向导——产品ID和使用者信息

(5)JAVA虚拟机安装,该选项可以选择也可以不选择。是否安装JAVA虚拟机对在Visual C++6.0环境下编写C++程序没有影响。如果选择安装,安装完该项后,计算机会自动重启,如图1-5所示。

(6)安装模式的选择,这里可以默认选中“Custom”单选按钮,然后单击“Next”按钮进入下一步,如图1-6所示。

图1-5 Visual C++6.0安装向导——JAVA虚拟机选项

图1-6 Visual C++6.0安装向导——安装模式

(7)安装路径的选择,在此,用户可以采用默认路径安装,也可以单击“Browse”按钮自定义选择安装时生成文件的存放路径,如图1-7所示。

(8)由于第(6)步中选择了Custom安装模式,因此在这里需要自定义安装选项。针对C++编程学习,确保Microsoft Visual C++6.0复选框选中即可,然后单击“Continue”按钮进入下一步,如图1-8所示,该图是选择安装Visual C++6.0的子功能和子系统的界面。

图1-7 Visual C++6.0安装向导——安装路径

图1-8 Visual C++6.0安装向导——功能选项

(9)单击“Continue”按钮后,将出现如图1-9所示的安装进度界面,该页面展示安装的进度。

(10)Visual C++6.0安装完毕后,计算机会自动跳出MSDN安装向导,互联网下载的安装文件可能不含MSDN安装包。如果没有MSDN安装包,用户可自行下载,然后运行该安装包的SETUP执行文件,安装过程与有MSDN安装包的Visual C++6.0自动安装是一样的,如图1-10所示。

图1-9 Visual C++6.0安装向导——安装过程

图1-10 安装MSDN向导

(11)为了使本机帮助功能最大化,一般使用“完全安装”类型,如图1-11所示。

注意 由于安装包可以另外下载,因此为了方便学习和工作,可以下载中文版MSDN进行安装。图1-11使用的安装包是中文版的。

(12)单击“完全安装”按钮后,将出现MSDN安装进度界面,如图1-12所示。

图1-11 MSDN安装选择

图1-12 MSDN安装进度界面

注意 安装MSDN是必要的,在软件研发过程中,如果想调用某函数,而又不清楚该函数的具体功能等情况,可以在脱机状态下查询该函数的具体情况。MSDN实质是一个本机帮助文件。

执行完这12个步骤后,Visual C++6.0(含MSDN)集成开发环境已经完全安装完毕。

1.1.2 Visual C++6.0开发环境

选择“开始”|“所有程序”|“Microsoft Visual Studio 6.0”|“Microsoft Visual C++6.0”命令,或者找到安装Visual C++6.0的子目录并双击MSDEV.EXE可执行文件,即可启动Visual C++6.0开发环境。为了使用方便,建议用户在桌面创建一个快捷方式。

启动Visual C++6.0后,可以看到如图1-13所示的界面。该界面是Visual C++6.0的主界面,编程过程将在这里进行。

图1-13 Visual C++6.0主界面

1.1.3 Visual C++6.0应用程序向导和项目创建

本节将学习如何使用Visual C++6.0的应用程序向导创建一个软件项目,但该软件不做任何事。

在软件开发过程中,人们很早就认识到应用程序的创建具有相似性和重复性,于是开发了一种功能,即自动化创建一类程序,大大提高了软件开发的效率,降低了软件编程的入门门槛。这种功能依托的就是应用程序向导。

【实例1-1】以下是使用Visual C++6.0应用程序向导创建项目的过程。

(1)选择“File”|“New”命令,或者直接按快捷键Ctrl+N,如图1-14所示。

(2)出现“New”对话框,选择“MFC AppWizard[exe]”选项,在右上角“Project name”文本框中填写项目名称“test”,然后单击“OK”按钮完成应用程序向导项目类型选择,如图1-15所示。

图1-14 创建新项目

图1-15 项目类型选择

(3)进入“MFC AppWizard”对话框,选中“Single document”单选按钮,这意味着生成的MFC程序是一个单文档应用程序。其他选项都使用默认值,单击“Next”按钮,也可以直接单击“Finish”按钮结束MFC应用程序向导设置,并生成MFC单文档应用程序框架程序,如图1-16所示。

(4)单击“Finish”按钮后,弹出“New Project Information”对话框,如图1-17所示,展示的是新建的应用程序的基本信息,用户从中可知本节创建的MFC程序的一些相关信息,简要说明如下。

·应用程序类型:支持Win32接口的单文档MFC程序。

·创建了4个类:应用程序类CTestApp类在“test.h”和“test.cpp”文件中;框架类CMainFrame类在“MainFrm.h”和“MainFrm.cpp”文件中;文档类CTestDoc类在“testDoc.h”和“testDoc.cpp”文件中;视图类CTestView类在“testView.h”和“testView.cpp”文件中。

·其他信息:主框架窗口中有工具栏和状态栏;视图类支持打印和打印预览;支持3D控件;该应用程序使用的是共享动态链接库(Dynamic Link Library,DLL);ActiveX控件可用;软件界面语言是简体中文。

图1-16 MFC程序类型设置

图1-17 新项目信息

注意 如果使用共享动态链接库编译生成的程序,在没有安装Microsoft Visual Studio 6.0的计算机中,就会出现缺少MFC42.DLL的运行错误。

为防止这种错误,可以将应用程序设置为使用MFC(Microsoft Foundation Classes)静态库的模式,选择“Project”|“Setting”命令,或按快捷键Alt+F7,出现如图1-18所示的对话框,在“Microsoft Foundation Classes”下拉列表中选择“Use MFC in a Static Library”选项。设置完成后单击“OK”按钮,重新编译执行该项目即可。

(5)按快捷键F5即可编译并运行该项目,运行界面如图1-19所示。

图1-18 修改MFC的DLL使用类型

图1-19 测试项目运行界面

从该运行界面可以检验步骤(4)中所说的部分新建项目信息,具有工具栏、状态栏和采用简体中文界面。

1.2 Visual C++6.0简介

本节主要介绍Visual C++6.0集成开发环境的各个子功能,同时也将详细介绍Visual C++6.0主界面菜单项的基本功能,最后介绍MSDN帮助功能的使用方法。

1.2.1 C/C++编译器

C和C++都是高级编程语言,C语言主要用于面向过程的程序设计,而C++是C的超集,即C是C++的子集。C++包含了原有的C语法规则,同时增加了面向对象和泛型编程的思想,支持类的定义、对象的创建和通用算法的使用。

注意 面向对象是一种思想,而不是某种编程语言的特权,C语言通过抽象数据类型的定义也可以进行面向对象设计。但就使用方便性而言,选择C++的类定义功能会比C语言抽象数据类型定义更为直观方便。培养面向对象的思想要经过长期的磨炼和实践。

高级编程语言要被计算机理解并执行,都要经过一个“翻译过程”,就如一个不懂英文的中国人要知道英语的意思,他需要一个翻译,将英语翻译成为汉语。在编程语言中,这种“翻译过程”有两种,即编译型和解释型。编译型语言是将该语言一次性编译成另外一种语言或机器语言,如C/C++;解释型语言是在运行时逐行或逐段解释成其他语言或机器语言,如HTML。

Visual C++6.0集成了C/C++的编译器,编译过程经过以下6个阶段。

①词法分析阶段:将关键字、变量和函数名等区分开,并存入词法表。

②语法分析阶段:将关键字、变量和函数名等组合起来的句子辨认出来,生成语法树。

③语义分析阶段:分析程序段和复杂循环结构。

④中间代码生成阶段:将源代码生成中间代码,等待进一步处理。

⑤代码优化阶段:将代码从时间效率和内存效率方面进行优化,尽量降低时间复杂度和内存消耗。

⑥目标代码生成阶段:生成其他语言或可执行文件。

注意 设计一个完美的编译程序并定义一套语言体系是一项复杂的系统工程。而一门高级程序设计语言的使用,则可使其变得相对简单得多。初学者理解编译过程理论,有助于为调试技术学习和进一步理论学习打下基础。

1.2.2 代码编辑器

打开1.1节创建的“test”项目,进入“test”项目的工作区和代码编辑区。切换到“FileView”选项卡,然后展开“test files”节点下面的“Source Files”文件夹,双击打开“testView.cpp”源文件,如图1-20所示。

该编辑器与普通的文本编辑器主要有以下两个不同点。

·彩色语法标记:将注释标记为绿色,将关键字标记为蓝色,使用Visual C++6.0创建的虚拟函数定义、消息函数定义和消息映射表项标记为灰色,其他源代码标记为黑色。

·智能提示功能:在用户输入一个对象指针时,如输入“MyObject->”,则在“->”输入完成后会出现一个下拉列表,列举出该对象的所有数据成员和成员函数,并且能够随着用户的输入自动定位。智能提示功能提高了用户输入速度,还可以防止用户因遗忘而浪费查找时间。

图1-20 编辑器窗口

1.2.3 资源编辑器和资源符号

打开1.1节创建的“test”项目,切换到“ResourceView”选项卡,在该选项卡中可以编辑菜单或对话框等资源;然后展开“test resources”节点下面的“Menu”文件夹,双击打开“IDR_MAINFRAME”资源项,如图1-21所示。这里可以看到该项目主窗口的菜单编辑界面,在这个界面中,用户可以自由地增加或删除菜单项。

在Visual C++6.0中,源代码和资源是分别编译的,源代码编译成中间代码时,资源则编译成二进制文件,在互不相同的编译途径中,连接程序通过一个“资源的标记”将源代码和资源文件联系起来,这个“资源的标记”就是资源符号。

如图1-22所示,在“ResourceView”选项卡中展开“String Table”文件夹,双击打开“String Table”资源项可以查看“test”项目所使用的全部资源符号。

图1-21 资源编辑器窗口

图1-22 资源符号

1.2.4 连接器和调试器

Visual C++6.0集成开发环境提供了编辑、连接、编译和运行的一体化。原本连接器要做的工作就是将C/C++编译器产生的OBJ文件和资源编译器生成的RES文件连接起来,而现在这个步骤在Visual C++6.0中对程序员来说是透明的。

程序从开发到使用中可能会发生两种错误,即语法错误和逻辑错误。

·语法错误是在编译时就会发现的,而在程序出现语法错误时,编译程序不再向下进行,因此也不会产生执行文件。这种错误可以通过编译器提示和语法使用手册进行排除,直至通过编译为止。

·逻辑错误是指通过了编译,并且生成了执行程序,在用户使用该软件中出现的逻辑上或业务上的矛盾或错误。同时,逻辑错误还包括运行时对数组等越界访问的语义错误。如a[5]数组,用户指定一个i的值为8,并执行了a[i]访问,则此时的行为是未定义的。而在此之前,该程序确实是编译通过的,并生成了执行文件。

注意 行为未定义是指执行某操作后,程序不确定会发生什么事,可能正常返回一个看似正常的数值,可能会导致程序中断,也可能会导致其他意想不到的结果。

调试器主要是为了查找逻辑错误而设置的,Visual C++6.0的调试器主要功能如下。

·可以很容易地设置断点。

·可以跟踪变量在运行时的变化。

·可以查看运行时函数调用的顺序。

·可以方便地查看内存内容。

1.2.5 Visual C++6.0的主要菜单项

Visual C++6.0是集成开发环境,同时也是一种软件,因此也具备一般应用软件的操作界面。Visual C++6.0的顶级菜单项有如下9个。

·File:提供对源文件、资源文件和项目的新建、打开和保存等功能。

·Edit:提供对源文件的编辑功能,包括复制、粘贴等。

·View:提供查看调试窗口或设置开发环境视图等功能。

·Insert:提供新建类或插入文件到项目等功能。

·Project:提供对整个项目的设置功能。

·Build:提供启动编译和运行等功能。

·Tools:提供一些额外的工具,以帮助开发者提高软件开发效率和质量。

·Window:提供窗口显示和切换功能。

·Help:提供帮助信息。

1.File菜单

File菜单如图1-23所示,各菜单项功能如下所述。

·New:新建,可以新建一个源文件(C++头文件、C++源文件、Bitmap文件、ASP文件、HTML文件、SQL脚本文件和文本文件等)、一个项目或一个工作台(Workspace)。

·Open:打开,可以打开源文件(C++头文件、C++源文件、Bitmap文件、ASP文件、HTML文件、SQL脚本文件和文本文件等)和工作区。

·Close:关闭,可以关闭当前操作的窗口。

·Open Workspace:打开一个工作区。

·Save Workspace:保存当前工作区。

·Close Workspace:关闭当前工作区。

·Save:保存当前窗口的源文件。

·Save As:将当前窗口源文件另存为其他格式。

·Save All:保存当前修改过的所有源文件。

·Page Setup:页面设置。

·Print:打印当前的源文件。

·Recent Files:打开最近打开过的源文件。

·Recent Workspace:打开最近打开过的工作区。

·Exit:退出Visual C++6.0集成开发环境。

2.Edit菜单

Edit菜单如图1-24所示,各菜单项功能如下所述。

·Undo:撤销上一步的操作。

·Redo:重做上一步的操作;如程序员复制了一段程序到源文件中后发现不需要这个程序段,使用Undo操作撤销复制操作,但马上发现这个程序段还是有用的,此时则可以使用Redo来重做复制程序段的工作。

·Cut:剪切。

·Copy:复制。

·Paste:粘贴。

·Delete:删除。

·Select All:选择当前源文件中所有内容。

·Find:查找当前源文件中的内容。

·Find in Files:在多个文件中查找特定字段内容。在此功能的高级选项中,可以通过逻辑组合字段进行准确查找,如查找在文件开头或在文件结尾的字段等。

·Replace:替换。

·Go To:使光标跳到指定的行或书签处。

·BookMarks:在光标处设置书签名称。如果以后要查找,可以通过“Go To”命令直接定位到该书签。

·Advanced:高级设置。

·Breakpoints:设置断点,用于调试时暂时中断程序往下运行,以此为起点来跟踪变量变化。

·List Members:成员列表,用于显示当前光标可用的数据成员、成员函数或全局的宏等。

·Type Info:类型信息。

·Parameter Info:参数信息。

·Complete Word:单词自动完成。

图1-23 File菜单

图1-24 Edit菜单

3.View菜单

View菜单如图1-25所示,各菜单项可提供以下功能。

·Class Wizard:类创建向导。

·Resource Symbols:资源符号。

·Resource Includes:资源包含文件设置。

·Full Screen:集成开发环境全屏设置。

·Workspace:将光标定位到工作区。

·Output:将光标定位到输出窗口。

·Debug Windows:调试窗口,子菜单含有内存查看、变量跟踪等。

·Refresh:刷新。

·Properties:源代码属性设置。

4.Insert菜单

Insert菜单如图1-26所示,各菜单项可提供以下功能。

·New Class:创建新类。

·New Form:创建新表。

·Resource:插入新资源。

·Resource Copy:插入资源副本。

·File As Text:插入源文件。

·New ATL Object:插入新的ATL对象。

5.Project菜单

Project菜单如图1-27所示,各菜单项可提供以下功能。

·Set Active Projects:选择活动项目,如本节的活动项目是“test”。

·Add To Project:添加文件到某项目中。

·Source Control:代码控制,如可使用Source Safe软件来控制多个程序员对同一个项目同时进行的代码共享研发。

·Dependencies:项目依赖,可以保证系统编译时的顺序,即先编译无依赖项的项目,再编译其有依赖项的项目。

·Settings:项目设置,可以设置该项目的各种参数,如编译方式、链接方式、字节对齐等。

·Export Makefile:导出Makefile文件。

·Insert Project into Workspace:将某项目插入工作区中。

图1-25 View菜单

图1-26 Insert菜单

在一个项目中,源文件往往很多,并且存放于若干个不同的目录中,Makefile中定义了一系列规则,如哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,或者其他更复杂的操作。Makefile的好处是“自动化编译”,写好Makefile文件后,只需要一个make命令,整个项目即完全自动编译,极大地提高了软件开发的效率。make是一个解释Makefile中的指令的命令工具,一般来说,当前大多数主流IDE都有这个命令,如Delphi的make、Visual C++的nmake、Linux下GNU的make。可见,Makefile成为一种在项目研发中使用的编译方法。

6.Build菜单

Build菜单如图1-28所示,各菜单项可提供以下功能。

说明 以下菜单项中出现的*一般代表具体的文件名,这里不指出文件名,以*代替。

·Compile*.cpp/*.h/*.rc2:编译源文件(C/C++源文件、C/C++头文件和资源文件)。

·Build*.exe:创建执行文件。

·Rebuild All:重新创建所有的中间文件和可执行文件。

·Batch Build:选择编译类型,为Release或Debug。

·Clean:清理所有已创建好的中间文件和可执行文件。

·Start Debug:开始调试。

·Debugger Remote Connection:远程连接调试器。

·Execute*.exe:执行已生成的执行文件。

·Set Active Configuration:更改动态配置,可更改为Release或Debug。

·Configurations:配置编译类型。

·Profile:帮助用户分析并发现程序运行的瓶颈,找到耗时所在,同时也能帮助用户发现不会被执行的代码,从而最终实现程序的优化。

注意 选择创建版本为Release或Debug。Debug通常称为调试版本,包含调试信息,并且不做任何优化,便于程序员调试程序。Release称为发布版本,往往进行了各种优化,程序在代码大小和运行速度上都是最优的,以便用户很好地使用。

图1-27 Project菜单

图1-28 Build菜单

7.Tools菜单

Tools菜单如图1-29所示,各菜单项可提供以下功能。

·Source Browser:源文件浏览器,可以浏览对象的类定义、来源等。

·Close Source Browser File:关闭源文件浏览器文件。

·Visual Component Manager:可以帮助开发人员在团队开发中方便地搜索、跟踪、排列、重用各种部件和其他项目部件,并方便地从Microsoft Repository中发布部件。

·Register Control:当使用MFC编写组件程序时,由于编译器不知道用户写的是否COM组件,因此它不会帮用户自动注册,这时,开发人员可以执行该命令来注册。

·Error Lookup:错误查看器,如编程中可以对可疑代码段进行错误返回值获取,根据获取的错误返回值可以在该查看器中查看错误说明。

·ActiveX Control Test Container:用于测试ActiveX控件的级联菜单功能。

·OLE/COM Object Viewer:OLE/COM对象查看器,可以很方便地查看指定组件的全部注册表信息和类型库信息。

·Spy++:一种基于Win32的实用工具,提供系统的进程、线程、窗口和窗口消息的图形视图。

·MFC Tracer:可以启用或禁用部分或全部MFC跟踪调试信息(TRACE和TRACEn宏)。

·Customize:自定义功能,可以设置集成开发环境的菜单项等。

·Options:自定义集成开发环境的界面或其他相关功能配置。

·Macro:运行宏操作。

·Record Quick Macro:记录新的宏。

·Play Quick Macro:运行新的宏。

注意 Spy++是一种实用性很强的工具,可以执行的操作:显示系统对象(包括进程、线程和窗口)之间关系的图形树;搜索指定的窗口、线程、进程或消息;查看选定的窗口、线程、进程或消息的属性;直接从视图中选择窗口、线程、进程或消息;通过鼠标定位,使用查找程序工具选择窗口;使用复杂消息日志选择参数设置消息选项。

8.Window菜单

Window菜单如图1-30所示,各菜单项可提供以下功能。

·New Window:新建一个窗口。

·Split:切分,可以将一个源文件窗口切分成若干个,方便程序员浏览同一个源文件的不同部分而无需上下拖动。关闭该源文件窗口再重新打开即可取消该功能。

·Docking View:集成开发环境的窗口对接。单击该命令可以使某些窗口最大化。

·Close:关闭当前源文件窗口。

·Close All:关闭全部源文件窗口。

·Next:查看下一个窗口。如果连续打开多个窗口,则这些窗口会按照打开的顺序排序。

·Previous:查看上一个窗口。

·Cascade:并排显示窗口。

·Tile Horizontally:纵向排列窗口。

·Tile Vertically:横向排列窗口。

·Windows:单击该命令会出现一个对话框,让用户选择已经打开的窗口。

图1-29 Tools菜单

图1-30 Window菜单

9.Help菜单

Help菜单如图1-31所示,各菜单项可提供以下功能。

·Contents:内容,调用MSDN的HTML帮助文档。

·Search:搜索,调用MSDN的HTML帮助文档,并将光标定位到搜索框。

·Index:索引,调用MSDN的HTML帮助文档,并将光标定位到索引框。

·Use Extension Help:使用外部帮助。选择该命令,如果选中某一个关键字并按F1键进行帮助调用,则将出现外部帮助选择对话框,可以选择外部帮助。

·Keyboard Map:查看集成开发环境的键盘快捷方式。

·Tip of the Day:显示今天的提示信息(tip),这是很多应用软件或集成开发环境提供的一项额外的人性化功能。

·Technical Support:技术支持,与Contents菜单命令类似,同样调用了MSDN的HTML帮助文档。

·Microsoft on the Web:Microsoft公司官方网站链接。

·About Visual C++:查看该集成开发环境的相关信息。

注意 在软件研发过程中,软件研发人员自己所研发的软件往往不是一个人完成,要了解别人使用的函数或类对象,如果客观条件不允许与原开发者沟通,则使用帮助文件的效率将会很明显。

图1-31 Help菜单

1.2.6 项目和解决方案

Visual C++6.0支持同一个解决方案上若干个项目的运行,前文所创建的“test”项目是在一个工作区上的单独项目。在Visual C++6.0集成开发环境中,自动生成的文件“.dsp”存储本项目的特定信息,而“.dsw”存储一个或多个项目的解决方案。

1.2.7 本机帮助和联机帮助

使用帮助在软件开发中是常用的手段,由于Visual C++6.0所涉及的技术繁多,可以安装的MSDN实际上只是所有Visual C++6.0帮助的一个子集,因此在本机帮助中得不到满意的答案时,可以使用联机帮助。帮助一般可以使用以下几种方式进行搜索。

·按F1键。如果没有选定任何关键字,按F1键将调出本机“MSDN HTML HELP”对话框,然后直接进行搜索即可。如果选定某一关键字,则跳出的对话框会直接定位找到的该关键字的相关解释。

·选择“Help”→“Content”命令将调用帮助文件,该文件将Visual C++6.0集成开发环境和Win32 SDK等按照章节编写。

·根据主题进行查询。选择“Help”→“Search”命令将调用输入关键字相关的主题和文章。

1.3 Visual C++6.0中的编程库

Visual C++6.0编程库指的是Visual C++6.0提供的编程库,主要包括4方面的内容,分别为C++标准库、C运行时(CRT)库、活动模板库(ATL)和微软基础类库(MFC)。

1.3.1 C++标准库

C++标准库中提供了C++程序的基本设施,它所包含的所有头文件都没有扩展名。C++标准库的内容总共在50个标准头文件中定义,其中18个提供了C库的功能。

C++标准库的内容可以分为10类,分别为语言支持、输入/输出、诊断、一般工具、字符串、容器、迭代器支持、算法、数值操作和本地化。

1.标准库中与语言支持功能相关的头文件以及头文件描述

·<cstddef>:定义宏NULL和offsetof以及其他标准类型size_t和ptrdiff_t。与对应的标准C头文件的区别是,NULL是C++空指针常量的补充定义,宏offsetof接收结构或者联合类型参数,只要它们没有成员指针类型的非静态成员即可。

·<limits>:提供与基本数据类型相关的定义。

·<climits>:提供与基本整型数据类型相关的C样式定义。

·<cfloat>:提供与基本浮点型数据类型相关的C样式定义。

·<cstdlib>:提供支持程序启动和终止的宏和函数。

·<new>:支持动态内存分配。

·<typeinfo>:支持变量在运行期间的类型标识。

·<exception>:支持异常处理。

·<cstdarg>:支持接受参数数量可变的函数,即在调用函数时,可以给函数传送数量不等的数据项,它定义了宏va_arg、va_end、va_start以及va_list类型。

·<csetjmp>:为C样式的非本地跳跃提供函数。

·<csignal>:为中断处理提供C样式支持。

2.标准库中支持流输入/输出的头文件以及头文件描述

·<iostream>:支持标准流cin、cout、cerr和clog的输入和输出,它还支持多字节字符标准流wcin、wcout、wcerr和wclog。

·<iomanip>:提供操纵程序,允许改变流的状态,从而改变输出的格式。

·<ios>:定义iostream的基类。

·<istream>:为管理输出流缓存区的输入定义模板类。

·<ostream>:为管理输出流缓存区的输出定义模板类。

·<sstream>:支持字符串的流输入和输出。

·<fstream>:支持文件的流输入和输出。

·<iosfwd>:为输入、输出对象提供向前的声明。

·<streambuf>:支持流输入和输出的缓存。

·<cstdio>:为标准流提供C样式的输入和输出。

·<cwchar>:支持多字节字符的C样式输入和输出。

3.标准库中与诊断功能相关的头文件以及头文件描述

·<stdexcept>:定义标准异常。异常是处理错误的方式。

·<cassert>:定义断言宏,用于检查运行期间的情形。

·<cerrno>:支持C样式的错误信息。

4.标准库中定义工具函数的头文件以及头文件描述

·<utility>:定义重载的关系运算符,简化关系运算符的写入;它还定义了pair类型,该类型是一种模板类型,可以存储一对值。

·<functional>:定义许多函数对象类型和支持函数对象的功能。

·<memory>:给容器、管理内存的函数和auto_ptr模板类定义标准内存分配器。

·<ctime>:支持系统时钟函数。

5.标准库中支持字符串处理的头文件以及头文件描述

·<string>:为字符串类型提供支持和定义,包括单字节字符串(由char组成)和多字节字符串(由wchar_t组成)。

·<cctype>:单字节字符类别。

·<cwctype>:多字节字符类别。

·<cstring>:为处理非空字节序列和内存块提供函数。

·<cwchar>:为处理、执行I/O和转换多字节字符序列提供函数。

·<cstdlib>:为把单字节字符串转换为数值、在多字节字符和多字节字符串之间转换提供函数。

6.标准库中定义容器类的模板的头文件以及头文件描述

·<vector>:定义vector序列模板,它是一个大小可以重新设置的数组类型,比普通数组更安全、灵活。

·<list>:定义list序列模板,它是一个序列的链表,常常在任意位置插入和删除元素。

·<deque>:定义deque序列模板,它支持在开始和结尾的高效插入和删除操作。

·<queue>:为队列(先进先出)数据结构定义序列适配器queue和priority_queue。

·<stack>:为堆栈(后进先出)数据结构定义序列适配器stack。

·<map>:map是一个关联容器类型,允许根据键值是唯一的,并且按照升序存储。

·<set>:set是一个关联容器类型,用于以升序方式存储唯一值。

·<bitset>:为固定长度的位序列定义bitset模板,它可以看做固定长度的紧凑型bool数组。

7.标准库中支持迭代器的头文件以及头文件描述

·<iterator>:给迭代器提供定义和支持。

8.标准库中有关算法的头文件以及头文件描述

·<algorithm>:提供一组基于算法的函数,包括置换、排序、合并和搜索。

·<cstdlib>:声明C标准库函数bsearch()和qsort(),进行搜索和排序。

·<ciso646>:允许在代码中使用and代替&&。

9.标准库中有关数值操作的头文件以及头文件描述

·<complex>:支持复杂数值的定义和操作。

·<valarray>:支持数值矢量的操作。

·<numeric>:在数值序列上定义一组一般数学操作,例如accumulate和inner_product。

·<cmath>:C数学库,其中还附加了重载函数,以支持C++约定。

·<cstdlib>:提供的函数可以提取整数的绝对值,对整数进行取余数操作等。

10.标准库中有关本地化的头文件以及头文件描述

·<locale>:提供的本地化包括字符类别、排序序列以及货币和日期表示。

·<clocale>:对本地化提供C样式支持。

1.3.2 C运行时库

C运行时库是程序在运行时所需要的库文件,通常运行时库是以Lib或Dll形式提供的。

Visual C++6.0提供了两种版本的C运行时库,一个版本供单线程应用程序调用;另一个版本供多线程应用程序调用。单线程运行时库与多线程运行时库有两个重大差别,具体如下。

·类似errno的全局变量,每个线程单独设置一个,这样从每个线程中可以获取正确的错误信息。

·多线程库中的数据结构以同步机制加以保护,这样可以避免访问时的冲突。

Visual C++6.0提供的多线程运行时库又分为静态链接库和动态链接库两类,而每一类运行时库又可再分为Debug版本和Release版本,因此Visual C++6.0共提供了6个运行时库,分别如表1-1所示。

表1-1 Visual C++6.0提供的C运行时库

C运行时库除了给用户提供必要的库函数调用(如memcpy、printf、malloc等)之外,还提供了另一个最重要的功能,即为应用程序添加启动函数。C运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,以及加载用户程序的入口函数。

1.3.3 活动模板库

活动模板库(ActiveX Template Library,ATL)是一套C++模板库。使用ATL能够快速地开发出高效、简洁的代码,同时对COM组件的开发提供最大限度的代码自动生成以及可视化支持。为了方便使用,从Microsoft Visual C++5.0版本开始,Microsoft把ATL集成到了Visual C++开发环境中。1998年9月推出的Visual Studio 6.0集成了ATL 3.0版本。目前,ATL已经成为Microsoft标准开发工具中的一个重要成员,日益受到C++开发人员的重视。

ATL的出现是为了解决使用传统的方法开发COM组件的高难度和高工作量的问题,它有着以下几点好处。

·ATL的基本目标就是使COM应用开发尽可能自动化,这就决定了ATL只面向COM开发提供支持。而且ATL对COM技术的支持达到淋漓尽致的地步:对COM开发的任何一个环节和过程,ATL都提供支持,并将与COM开发相关的众多工具集成到一个统一的编程环境中;对于COM/ActiveX的各种应用,ATL也都提供了完善的Wizard支持。这些都极大地方便了开发者的使用,使开发者能够把注意力集中在与应用本身相关的逻辑上。

·ATL采用了特定的基本实现技术,摆脱了大量冗余代码,所以使用ATL开发出来的COM应用的代码简练高效。ATL在实现上尽可能采用优化技术,甚至在其内部提供了所有C/C++开发的程序所必须具有的C启动代码的替代部分。同时,ATL产生的代码在运行时不需要依赖于类似MFC程序所需要的庞大的代码模块,包含在最终模块中的功能是用户认为最基本和必需的。这些措施使采用ATL开发的COM组件(包括ActiveX Control)可以在网络环境下实现应用的分布式组件结构。

·ATL的各个版本都很好地支持Microsoft的基于COM的各种新的组件技术(如MTS、ASP等),ATL对新技术的反应速度大大快于MFC。ATL已经成为Microsoft支持COM应用开发的主要开发工具,因此COM技术方面的新进展在很短的时间内都会在ATL中得到体现。这使开发者使用ATL进行COM编程可以得到直接使用COM SDK编程同样的灵活性和强大的功能。

1.3.4 微软基础类库

微软基础类库(Microsoft Foundation Classes,MFC)是微软提供的用于在C++环境下编写应用程序的一个框架和引擎。Visual C++是Windows下开发人员使用的专业C++SDK,MFC就是挂在它之上的一个辅助软件开发包。MFC是与Visual C++血肉相连的部分,它同BC++集成的VCL一样,是一个非外挂式的软件包类库,不同的是MFC是微软为Visual C++专门提供的。

MFC是Windows API与C++的结合,是对API函数的专用C++封装,隐藏了程序员在Windows下用C++和MFC开发软件时的大量细节。MFC不仅提供了用于界面开发的类库,还提供了很多类库用于在Windows环境下实现内部处理的类,比如数据库访问、线程管理等。

1.4 Win32基本应用程序的创建

本节将讲解Win32的基本概念以及Win32应用程序的创建,并在最后一节讲解如何在Win32应用程序中使用Visual C++6.0的调试功能。

1.4.1 AppWizard应用程序向导

Win32一般是指Windows的32位操作系统。Windows操作系统从16位开始,到32位(Win 98/Me/2000/NT/XP/2003等),现在是64位(XP有64位版的,例如Vista是典型的64位操作系统),现在Win32编程一般被指在Windows平台下进行软件开发。而Win32 SDK(Software Development Kit,软件开发包)则是在Windows的32位操作系统下提供的软件编程接口,为Windows操作系统的应用软件提供可扩展的函数接口。

【实例1-2】Visual C++6.0可以很方便地创建Win32程序,过程如下。

(1)使用Visual C++6.0创建新项目。

(2)选择创建Win32应用程序,可将项目命名为“Win32”或其他用户自定义名称。选择应用程序类型和设置项目名称,如图1-32所示。

(3)选择创建简单的Win32应用程序,设置某特定应用程序的子类型。这里选中“A typical“Hello World!”application.”单选按钮,然后单击“Finish”按钮结束向导设置,如图1-33所示。

图1-32 选择创建Win32应用程序

图1-33 创建Win32类型应用程序

注意 如果选中“An empty project.”单选按钮,则生成一个空的项目,里面没有任何源文件;如果选中“A simple Win32 application.”单选按钮,则生成一个含有winMain()空函数的文件,不会生成有界面的Win32应用程序;如需创建界面,需要用户自己添加窗口函数等代码。

1.4.2 生成Win32应用程序

前文创建的Win32应用程序生成了包含winMain()函数的C++源文件,Win32应用程序的开发界面如图1-34所示。直接按F5键编译并运行该程序,运行效果如图1-35所示。

图1-34 Win32应用程序开发界面

图1-35 Win32应用程序运行结果界面

注意 Win32应用程序是Windows程序设计的基础和核心,本书所采用的MFC应用程序实质上是对Win32应用程序的封装和整理,把面向过程化的Win32应用程序编写转换成面向对象的MFC框架编程。

【实例1-3】打开1.3.1小节创建的Win32应用程序,查看Win32.cpp文件,代码如下。读者现在对这段程序可能不理解,本书在以后的章节会逐步讲解。

01      #include "stdafx.h"
02      #include "resource.h"
03      #define MAX_LOADSTRING 100
04      HINSTANCE hInst;                                                            //全局句柄
05      TCHAR szTitle[MAX_LOADSTRING];
06      TCHAR szWindowClass[MAX_LOADSTRING];
07      ATOM                        MyRegisterClass(HINSTANCE hInstance);      //注册窗口函数声明
08      BOOL                        InitInstance(HINSTANCE, int);                  //初始化函数声明
09      LRESULT       CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);      //窗口函数声明
10      LRESULT CALLBACK      About(HWND, UINT, WPARAM, LPARAM);            // About消息函数声明
11      int APIENTRY WinMain(HINSTANCE hInstance,
12                           HINSTANCE hPrevInstance,
13                           LPSTR     lpCmdLine,
14                           int       nCmdShow)                               //主函数
15      {
16            MSG msg;                                                                  //定义消息
17            HACCEL hAccelTable;
18            LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
19            LoadString(hInstance, IDC_WIN32, szWindowClass, MAX_LOADSTRING);
20            MyRegisterClass(hInstance);                                    //注册初始句柄
21            if (!InitInstance (hInstance, nCmdShow))                  //初始化窗口
22            {
23                  return FALSE;
24            }
25            hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WIN32);
26            while (GetMessage(&msg, NULL, 0, 0))                        //消息循环处理
27            {
28                  if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
29                  {
30                        TranslateMessage(&msg);
31                        DispatchMessage(&msg);
32                  }
33            }
34            return msg.wParam;                                          //返回消息附加参数
35
36      }
37      ATOM MyRegisterClass(HINSTANCE hInstance)
38      {                                                                        //窗口类型定义
39            WNDCLASSEX wcex;                                                //定义扩展的窗口类型
40            wcex.cbSize = sizeof(WNDCLASSEX);                        //窗口大小
41            wcex.style                  = CS_HREDRAW | CS_VREDRAW;      //窗口风格
42            wcex.lpfnWndProc      = (WNDPROC)WndProc;                  //窗口函数指定
43            wcex.cbClsExtra            = 0;
44            wcex.cbWndExtra            = 0;
45            wcex.hInstance            = hInstance;                        //窗口句柄指定
46            wcex.hIcon                  = LoadIcon(hInstance, (LPCTSTR)IDI_WIN32);
47            wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
48            wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
49            wcex.lpszMenuName      = (LPCSTR)IDC_WIN32;
50            wcex.lpszClassName      = szWindowClass;
51            wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
52            return RegisterClassEx(&wcex);      //注册该窗口类型
53      }
54      BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
55      {                                                //初始化函数(初始化句柄,窗口显示命令)
56         HWND hWnd;
57         hInst = hInstance;
58         hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
59            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
60                                                      //创建窗口
61         if (!hWnd)
62         {
63            return FALSE;
64         }
65         ShowWindow(hWnd, nCmdShow);            //显示窗口
66         UpdateWindow(hWnd);                        //更新窗口
67         return TRUE;
68      }
69      LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
70            LPARAM lParam)                        //窗口函数(窗口句柄,消息,消息附加参数,子窗口句柄)
71      {
72            int wmId, wmEvent;                  //定义窗口事件
73            PAINTSTRUCT ps;                        //定义画图结构
74            HDC hdc;                                    //定义窗口句柄
75            TCHAR szHello[MAX_LOADSTRING];      //定义“Hello,World”字符串
76            LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
77                                                      //导入IDS_HELLO到szHello
78            switch (message)                        //消息分类处理
79            {
80                  case WM_COMMAND:                  //命令消息
81                        wmId    = LOWORD(wParam);
82                        wmEvent = HIWORD(wParam);
83                        // Parse the menu selections:
84                        switch (wmId)
85                        {
86                              case IDM_ABOUT:
87                                 DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd,
88                                    (DLGPROC)About);
89                                 break;
90                              case IDM_EXIT:
91                                 DestroyWindow(hWnd);
92                                 break;
93                              default:
94                                 return DefWindowProc(hWnd, message, wParam, lParam);
95                        }
96                        break;
97                  case WM_PAINT:                  //重画消息
98                        hdc = BeginPaint(hWnd, &ps);
99                        // TODO: Add any drawing code here...
100                        RECT rt;
101                        GetClientRect(hWnd, &rt);
102                        DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
103                        EndPaint(hWnd, &ps);
104                        break;
105                  case WM_DESTROY:                        //销毁消息
106                        PostQuitMessage(0);
107                        break;
108                  default:
109                        return DefWindowProc(hWnd, message, wParam, lParam);
110         }
111         return 0;
112      }
113      LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM
114                              lParam)
115      {                                                      //  Win32应用程序About对话框消息处理函数
116            switch (message)
117            {
118                  case WM_INITDIALOG:                  //判断是否建立对话框
119                              return TRUE;
120                  case WM_COMMAND:                        //判断是否有命令消息
121                        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
122                        {                                    //如果命令消息是IDOK或IDCANCEL
123                              EndDialog(hDlg, LOWORD(wParam));
124                              return TRUE;                  //结束以hDlg为句柄的对话框
125                        }
126                        break;
127            }
128          return FALSE;
129      }

【代码说明】Win32应用程序对于初学者来说乍一看会觉得有点复杂,但无非就是以下几个部分。

·第11行WinMain()函数:负责调用其他功能函数。

·第37行MyRegisterClass()函数:负责注册窗口的各项信息。

·第54行InitInstance()函数:负责初始化。

·第69行WndProc()函数:负责处理消息循环。在函数体内的第84行、97行和105行可以看到用于Windows消息处理的switch语句,分别定义命令消息、重画消息和销毁消息等。

·第113行About()函数:负责About对话框的创建,代码第116~127行就是Windows消息,和主窗口的机制是一样的,但这里要等待用户单击调用对话框的按钮。

注意 Windows应用程序就是一个基于消息处理的应用程序,因此WndProc()函数就是等待外界或操作系统给它发送消息,如重画界面、敲击键盘或鼠标单击等。

从WinMain()函数可以看到Win32应用程序中的运行过程,说明如下。

①调用MyRegisterClass()函数注册窗口,设置窗口的各种参数。

②调用InitInstance()函数初始化窗口。在InitInstance()函数体内通过调用Win32 SDK的CreateWindow()函数来创建窗口。

③进入消息循环进行消息处理,源代码如下。

01            while (GetMessage(&msg, NULL, 0, 0))                        //获取消息
02            {
03                  if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
04                  {
05                        TranslateMessage(&msg);                              //翻译消息
06                        DispatchMessage(&msg);                              //处理消息
07                  }
08            }

【代码说明】代码第05、06行分别调用了Win32 API的消息处理函数,表示翻译消息和处理消息函数。

编程陷阱 请注意Win32 API和MFC函数一般不是互通的,但MFC应用程序中可以直接使用前者,反之则不行。

1.4.3 Visual C++6.0的调试:变量跟踪和函数调用栈

变量跟踪和函数调用栈查看是Visual C++6.0常用调试方法。

【实例1-4】以1.4.2小节的Win32应用程序为例,在WndProc()函数的“switch(message)case WM_PAINT”程序段插入一些代码,用来测试变量跟踪信息。

01      LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
02            LPARAM lParam)                                    //窗口函数(窗口句柄,消息,
03                                                                  //消息附加参数,子窗口句柄)
04      {
05            …
06            int a=0;                                                //定义a整型变量
07            …                                                      //其他窗口函数代码
08            swiitch(message)                                    //消息处理函数
09            {
10                  …                                                //其他消息处理程序段
11                  case WM_PAINT:                              //重画消息
12                        hdc = BeginPaint(hWnd, &ps);      //开始重画
13                        RECT rt;
14                        GetClientRect(hWnd, &rt);            //获取客户区
15                        for(a=0;a<10;a++)                        // a在for循环中变化
16                        {
17                              a;
18                        }                                          //新增的程序段,用于调试知识讲解
19                        DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
20                                                                  //画文字
21                        EndPaint(hWnd, &ps);                  //结束重画
22                        break;
23            }
24            …
25      }

【代码说明】代码第11行定义的是重画消息处理段,表示如果窗口接到重画消息,则执行第12行开始的代码,直到第22行的break语句。代码第15~18行是一个for循环语句,这里将输出10个数值。

说明 Win32 API设计体系是面向过程的,也就是全面的自顶向下的设计思路,因此,在消息处理的架构中,将消息分门别类进行处理,也是一种常用的自顶向下、逐步细化的处理方法。

【运行效果】将光标定位到for循环的程序段中,选择“Edit”→“Breakpoints”命令,在for语句中添加一个断点,然后按F5键进行调试,如图1-36所示。

在调试过程中,程序中断所在位置用黄色箭头标记。一般开始调试时,程序中断位置就在用户设置的第一个断点处。用户可以按F10键进行逐步调试,并观察变量a的变化过程,思考该过程是否按照自己的逻辑思路变化。

函数调用栈查看可通过“Debug”悬浮窗口中打开,如图1-37所示,单击调试窗口功能按钮,打开“Call Stack”窗口如图1-38所示,即展示了程序运行时的函数调用顺序栈。从该窗口可以看到,函数调用与前文所分析的顺序吻合。

图1-36 调试界面

图1-37 “Debug”悬浮窗口

图1-38 “Call Stack”窗口

1.5 Microsoft应用程序框架

本节主要介绍Microsoft的应用程序框架,着重介绍MFC的框架,让读者对Visual C++6.0的使用有个代码框架的概念。

1.5.1 全局对象

通过1.1节的学习,可以发现用Visual C++6.0创建一个MFC程序是非常容易的。细心的读者在阅读源代码的过程中可能会发现,MFC程序没有主函数,这也让很多习惯于C语言面向对象编程的读者感到无从下手,觉得不能理解程序的运行顺序。

事实上,任何软件程序都有入口,否则操作系统无法调用它,也就是说无入口的软件程序是不能执行的。在到处都是类定义和类实现的MFC程序中,可以在创建的项目的.cpp源文件中找到一个在全局区域定义的对象,例如1.1节中的test.cpp源文件中的对象如下,该对象就是MFC程序的入口。

CtestApp theApp;                  //全局应用程序对象定义

简单来看,MFC程序可以看做定义部分和创建部分。

·定义部分:文档类、视图类、框架类和应用程序类的定义及类成员函数的实现。该过程是不分配内存空间的。就像CView是一个类,int是一个数据类型,也就是一个特殊的类。在Visual C++中,int这个特殊类型的类的定义并不实际分配空间,只有执行了“int object;”语句后才会分配实际的内存空间。在Win32环境下,分配了4字节的内存空间用于存放object变量的数值。

·创建部分:分配了实际内存空间,并将创建的对象放在实际内存空间中。

说明 MFC的创建起源于全局对象的创建,在这个对象创建的过程中,一系列相互关联的类对象也在内存中诞生了,并将这个软件展示在用户眼前。

1.5.2 MFC的消息映射和消息分类

根据处理函数和处理过程的不同,MFC主要处理如下3类消息。

·Windows消息。其前缀以“WM_”打头,WM_COMMAND例外。

·控制通知消息。这是控制子窗口送给父窗口的WM_COMMAND通知消息。

·命令消息。这是来自菜单、工具条按钮、快捷键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的消息。

注意 本书第二篇会详细讲解各种消息的意义和使用,在这里了解消息种类即可。

MFC的消息映射过程是Windows消息直接送给MFC窗口过程处理,窗口过程调用对应的消息处理函数。一般由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。

1.6 实例:编写第一个C++程序:Hello,C++!

本节通过空项目来创建C++程序,这个创建过程很重要,第2章的所有实例都将基于这种创建方法,这也是学习C++语言理论进行实验的基本前提。

【实例1-5】创建C++程序“Hello,C++!”的过程如下。

(1)创建一个新项目。

(2)选择创建一个“Win32 Console Application”程序,命名为FirstProgram,如图1-39所示。

(3)选中“An empty project.”单选按钮,创建一个空的项目,如图1-40所示,完成选择Win32 Console Application应用程序的子类型。

图1-39 选择程序类别并命名

图1-40 选择项目类型

(4)由于该项目的根目录是空的,因此需要用户自己创建C++源文件。如图1-41所示,在工作区文件视图中打开“FileView”选项卡,在“Source Files”文件夹下添加新文件。

(5)新建源文件(或插入已有源文件)。打开不存在的C++源文件,输入自定义文件名称即可,Visual C++6.0支持这种创建C++源文件的方式,如图1-42所示。

图1-41 新建C++源文件

图1-42 新建C++源文件名称

(6)如图1-43所示,打开“Source Files”文件夹下的空源文件main.cpp,在项目的源文件编辑器中编辑源代码,写入第一个C++源程序。

(7)按F5键运行该程序,运行结果如图1-44所示打开一个命令行窗口。

本节所使用的C++代码比较简单,不过对于没有C++基础的读者来说,这里还是有一些需要说明的,而且追究程序细节也是程序语言理论学习中一项有意义的事。C++代码如下。

01      #include <iostream>                        //包含输入输出流文件
02      using namespace std;                        //指定使用标准名称空间“std”
03      int main()
04      {
05            cout<<"Hello,C++!";                  //输出流对象cout使用<<运算符输出“Hello,C++!”串
06            cin.get();                              //等待接受键盘敲击
07            return 0;                              //将程序运行状态返回给操作系统
08      }

图1-43 填写C++代码

图1-44 第一个C++程序的运行结果

【代码说明】

·第01行的#include<iostream>表示main.cpp源文件可以使用输入/输出流所定义的对象、变量等。C++98标准之前是使用#include<iostream.h>的,C++98标准进行这种制定的目的是区分用户定义的和C++语言标准的,没有“.h”后缀的一律为C++语言标准头文件。#include“”和#include<>的区别在于,#include“”预编译命令让源程序先在当前项目目录下寻找头文件,如果找不到,再到Visual C++6.0标准头文件目录下去找;而#include<>命令告诉编译器直接去Visual C++6.0标准头文件目录去找该头文件。

·第02行的using namespace std;声明以下的同一个源文件内,都可以使用std名称空间中的内容,这也是C++98标准防止标准变量和用户定义变量冲突的一种方法。

·第03行的int main()是C++程序的入口,该入口是一个函数,这个函数的返回值是int类型。该函数的调用主体就是操作系统,当操作系统调用该函数得到一个为0的返回值后(return 0),操作系统就知道该程序是正常退出了。

·第05行的cout<<“Hello,C++!”是运行结果的输出语句。cout是iostream头文件定义的一个输出流对象,该对象有一个重载方法“<<”,而该重载方法接收的参数为“Hello,C++!”字符串。“<<”运算符本来的功能是向左移位操作,在cout对象中实现的是输出重载功能,其调用就相当于语句“cout.operator<<(“Hello,C++!”);”。

·第06行的cin.get()是用户为了防止输出程序窗口过快显示而设置的,cin是输入流对象,这里调用了该对象的get()成员函数,用于接收用户一个输入,接收之后程序很快就返回操作系统并退出。

编程陷阱 std是标准名称空间,在没有其他名称空间存在时,可以使用本例的前置定义的方式;如果有其他名称空间,这样的定义方式容易导致歧义,最好使用std::cout的方式进行定义,以明确每个关键字的名称空间。

1.7 实例:创建第一个MFC程序:Hello,MFC!

本节主要讲解如何创建MFC程序,1.1小节已经介绍了MFC程序创建过程,本节将在1.1小节创建的“test”项目的基础上简单介绍MFC程序的输出。

【实例1-6】在“test”项目中打开“FilesView”选项卡,打开testView.cpp文件,修改void Ctest View::OnDraw(CDCpdc)函数,代码如下。

01      void CtestView::OnDraw(CDC* pdc)
02      {
03            CtestDoc* pDoc = GetDocument();            //自动生成的代码,获取当前文档
04            ASSERT_VALID(pDoc);                              //自动生成的代码,判断当前文档是否有效
05           //以下两行为新增代码
06            tagRECT a = {100,100,200,200};                  //定义一个矩形a
07            pDC->DrawText("Hello,MFC!",&a,1);            //调用MFC类对象的函数打印字符串
08      }

【代码说明】新增的两行MFC程序也比较简单,该函数负责视图类界面描画,因此在这里添加的函数一般都是为视图类添加额外的描画任务。

·第06行的tagRECT a={100,100,200,200}定义了一个矩形结构体a。该矩形的4个参数分别描述了左上角和右下角的点的x和y坐标值。

·第07行的pDC->DrawText("Hello,MFC!",&a,1)表示DrawText()函数调用了pDC对象指针的。

【运行效果】按F5键编译并运行该程序,可以得到如图1-45所示的运行界面。

图1-45 “Hello MFC!”运行界面

1.8 小结

本章概要介绍了Visual C++6.0开发环境的安装和界面的一些基本操作,读者通过阅读本章,应该掌握的知识如下。

·Visual C++6.0及其MSDN的安装。

·Visual C++6.0菜单的功能。

·创建各种类型Visual C++项目的方法。

·Visual C++6.0的应用程序框架。

1.9 习题

一、填空题

1.在Visual C++集成开发环境中,自动生成的文件________存储本项目的特定信息,________存储一个或多个项目的解决方案。

2.SDK的英文全称是________,中文意思是________。

3.MFC主要处理________、________和________三类消息。

二、上机实践

1.编写一个小程序,在命令行窗口输出“北京欢迎你!”。

【提示】本题主要要求读者学习C++入门知识,初步了解C++程序设计技术。

【关键代码】

std::cout<<"北京欢迎你!"<<std::endl;

2.在MFC文档视图程序中,编写一个小程序,输出“北京欢迎你!”。

【提示】本题主要要求读者学习MFC入门知识,初步了解MFC程序设计技术。

【关键代码】

pDC->DrawText("北京欢迎你!",&a,1);