VC++60 第十六章 VC++开发工具和MFC基础类库(三)

来源:互联网 发布:2016上半年网络流行语 编辑:程序博客网 时间:2024/05/22 04:54

VC++60 第十六章 VC++开发工具和MFC基础类库(三)

16.3 Windows应用程序的运行机制

 

Windows应用程序的特点

Windows编程与DOS环境下编程相比有很大的不同。Windows要求以一种全新的思维方式进行程序设计,Windows应用程序主要表现为以下四个特点:

1)事件驱动的程序设计
   传统的MS-DOS程序主要采用顺序的、关联的、过程驱动的程序设计方法。一个程序是一系列预先定义好的操作序列的组合,它具有一定的开头、中间过程和结束。程序直接控制程序事件和过程的顺序。这样的程序设计方法是面向程序而不是面向用户的,交互性差,用户界面不够友好,因为它强迫用户按照某种不可更改的模式进行工作。它的基本模型如图1.1所示。
    事件驱动程序设计是一种全新的程序设计方法,它不是由事件的顺序来控制,而是由事件的发生来控制,而这种事件的发生是随机的、不确定的,并没有预定的顺序,这样就允许程序的的用户用各种合理的顺序来安排程序的流程。对于需要用户交互的应用程序来说,事件驱动的程序设计有着过程驱动方法无法替代的优点。它是一种面向用户的程序设计方法,它在程序设计过程中除了完成所需功能之外,更多的考虑了用户可能的各种输入,并针对性的设计相应的处理程序。它是一种“被动”式程序设计方法,程序开始运行时,处于等待用户输入事件状态,然后取得事件并作出相应反应,处理完毕又返回并处于等待事件状态。它的框图如图chap16-10所示::

VC++60 <wbr>第十六章 <wbr>VC++开发工具和MFC基础类库(三)
图chap16-10

2) 消息循环与输入

    事件驱动围绕着消息的产生与处理展开,消息是一种报告有关事件发生的通知。事件驱动是靠消息循环机制来实现的。    
    消息类似于DOS下的用户输入,但比DOS的输入来源要广,Windows应用程序的消息来源有以下四种:
    (1)输入消息:包括键盘和鼠标的输入。这一类消息首先放在系统消息队列中,然后由Windows将它们送入应用程序消息队列中,由应用程序来处理消息。
    (2)控制消息:用来与Windows的控制对象,如列表框、按钮、检查框等进行双向通信。当用户在列表框中改动当前选择或改变了检查框的状态时发出此类消息。这类消息一般不经过应用程序消息队列,而是直接发送到控制对象上去。
    (3)系统消息:对程序化的事件或系统时钟中断作出反应。一些系统消息,象DDE消息(动态数据交换消息)要通过Windows的系统消息队列,而有的则不通过系统消息队列而直接送入应用程序的消息队列,如创建窗口消息。
    (4)用户消息:这是程序员自己定义并在应用程序中主动发出的,一般由应用程序的某一部分内部处理。
    在DOS应用程序下,可以通过getchar()、getch()等函数直接等待键盘输入,并直接向屏幕输出。而在Windows下,由于允许多个任务同时运行,应用程序的输入输出是由Windows来统一管理的。
    Windows操作系统包括三个内核基本元件:GDI, KERNEL ,USER。其中GDI(图形设备接口)负责在屏幕上绘制像素、打印硬拷贝输出,绘制用户界面包括窗口、菜单、对话框等。系统内核KERNEL支持与操作系统密切相关的功能:如进程加载,文本切换、文件I/O,以及内存管理、线程管理等。USER为所有的用户界面对象提供支持,它用于接收和管理所有输入消息、系统消息并把它们发给相应的窗口的消息队列。消息队列是一个系统定义的内存块,用于临时存储消息;或是把消息直接发给窗口过程。每个窗口维护自己的消息队列,并从中取出消息,利用窗口函数进行处理。

3) 图形输出

    Windows程序不仅在输入上与DOS程序不同,而且在程序输出上也与DOS有着很大不同,主要表现为:
    1.DOS程序独占整个显示屏幕,其他程序在后台等待。而Windows的每一个应用程序对屏幕的一部分进行处理。DOS程序可以直接往屏幕上输出,而Windows是一个多窗口的操作系统,由操作系统来统一管理屏幕输出;每个窗口要输出内容时,必须首先向操作系统发出请求(GDI请求),由操作系统完成实际的屏幕输出工作。
    2.Windows程序的所有输出都是图形。Windows提供了丰富的图形函数用于图形输出,这对输出图形是相当方便的,但是由于字符也被作为图形来处理,输出时的定位要比DOS复杂的多。
    比如,在DOS字符方式下,我们可以写出如下程序用于输出两行文字:
    printf(“Hello,\n”);
    printf(“This is DOS program.\n”);
    而在Windows下要输出这两行文字所做的工作要复杂的多。因为Windows输出是基于图形的,它输出文本时不会象DOS那样自动换行,而必须以像素为单位精确定位每一行的输出位置。另外,由于Windows提供了丰富的字体,所以在计算坐标偏移量时还必须知道当前所用字体的高度和宽度。
    3.Windows下的输出是设备无关的。在DOS下编写过Foxpro程序的读者常常会有这样的体会,在编写打印报表程序时,要针对不同的打印机在程序中插入不同的打印控制码,用以控制换页、字体设置等选项。这样的程序编写起来繁琐,而且不容易移植(因为换一台不同型号的打印机就要重新修改程序)。而Windows下的应用程序使用图形设备接口(GDI)来进行图形输出。GDI屏蔽了不同设备的差异,提供了设备无关的图形输出能力,Windows应用程序只要发出设备无关的GDI请求(如调用Rectangle画一个矩形),由GDI去完成实际的图形输出操作。对于一台具有打印矩形功能的PostScript打印机来说,GDI可能只需要将矩形数据传给驱动程序就可以了,然后由驱动程序产生PostScript命令绘制出相应的矩形;而对于一台没有矩形输出功能的点阵打印机来说,GDI可能需要将矩形转化为四条线,然后向驱动程序发出画线的指令,在打印机上输出矩形。当然,这两种输出在用户看来并没有什么区别。
    Windows的图形输出是由图形设备接口(GDI)来完成的,GDI是系统原始的图形输出库,它用于在屏幕上输出像素、在打印机上输出硬拷贝以及绘制Windows用户界面。
    GDI提供两种基本服务:创建图形输出和存储图象。GDI提供了大量用于图形输出的函数,这些函数接收应用程序发出来的绘图请求、处理绘图数据并根据当前使用设备调用相应的设备驱动程序产生绘图输出。这些绘图函数分为三类:一是文字输出,二是矢量图形函数,用于画线、圆等几何图形,三是光栅(位图)图形函数,用于绘制位图。
    GDI识别四种类型的设备:显示屏幕、硬拷贝设备(打印机、绘图机)、位图和图元文件。前两者是物理设备,后两者是伪设备。一个伪设备提供了一种在RAM里或磁盘里存储图象的方法。位图存放的是图形的点位信息,占用较多的内存,但速度很快。图元文件保存的是GDI函数的调用和调用参数,占用内存较少,但依赖于GDI,因此不可能用某个设备来创建图元文件,而且速度比位图要慢。
    GDI的图形输出是面向窗口的,面向窗口包含两层含义:
    (1)每个窗口作为一个独立的绘图接口来处理,有它自己的绘图坐标。当程序在一个窗口中绘图时,首先建立缺省的绘图坐标,原点(0,0)位于窗口用户区的左上角。每个窗口必须独立的维护自己的输出。
    (2)绘图仅对于本窗口有效,图形在窗口边界会被自动裁剪,也就是说窗口中的每一个图形都不会越出边界。即使想越出边界,也是不可能的,窗口会自动的防止其他窗口传过来的任何像素。这样,你在窗口内绘图时,就不必担心会偶然覆盖其他程序的窗口,从而保证了Windows下同时运行多个任务时各个窗口的独立性。

4) 用户界面对象

    Windows支持丰富的用户接口对象,包括:窗口、图标、菜单、对话框等等。程序员只需简单的几十行代码,就可以设计出一个非常漂亮的图形用户界面。而在DOS环境下,则需要大量的代码来完成同样的工作,而且效果也没有Windows提供的那么好。本书前面各章就是介绍这些用户界面对象的设计和使用的,这里就不再重复了。

 

应用程序的入口、运行和退出

在DOS下,程序的执行是从main函数开始的。在Windows下,对应的函数是WinMain。但是,如果浏览Hello程序的所有的方法和全局函数,是找不到WinMain函数的。MFC考虑到典型的Windows程序需要的大部分初始化工作都是标准化的,因此把WinMain函数隐藏在应用程序的框架中,编译时会自动将该函数链接到可执行文件中。程序员可以重写WinMain函数,但一般不需要这么做。

应用程序执行时,Windows自动调用应用程序框架内部的WinMain函数。WinMain函数会查找该应用程序的一个全局构造对象,这个对象是由CWinApp派生类构造的,有且只有一个。它就是theApp全局对象,在程序启动时它已经被构造好了。随后,WinMain将调用这个对象的InitApplication和InitInstance成员函数,完成应用程序实例的初始化工作。随后,WinMain调用Run成员函数,运行应用程序的消息循环。在程序结束时,WinMain调用AfxWinTerm函数,做一些清理工作。

WinMain在初始化应用程序实例后,就调用Run函数来处理消息循环。Run成员函数不断执行消息循环,检查消息队列中有没有消息。如果有消息,Run将其派遣,交由框架去处理,然后返回继续消息循环。如果没有消息,Run将调用OnIdle来做用户或框架可能需要在空闲时才做的工作,象后面我们讲到的用户接口更新消息处理等。如果既没有消息要处理,也没有空闲时的处理工作要做,则应用程序将一直等待,直到有事件发生。当应用程序结束时,Run将调用ExitInstance。

当用户通过选择菜单命令来关闭应用程序后,Windowes就关闭主框架窗口终止应用程序。此时,应用程序类首先删除m_pMainWnd主框架窗口对象,然后退出Run函数,进而退出WinMain,退出后再删除theApp对象。

0 0
原创粉丝点击