1、Visual C+在Windows应用程序上的编程方法仍可分为两类:非Window编程,如控制台程序(一种与早期DOS相兼容的程序,用来学习基本C+的编程思想)Window编程直接调用Windows提供的Win32 API(应用程序接口)函数开发Windows应用程序,像Windows程序设计(第五版)该书所讨论的就是这种方式用用Visual C+Visual C+所提供的所提供的MFC(Microsoft MFC(Microsoft Foundation ClassFoundation Class,微软基础类微软基础类)库中库中的的 类类 及其功能函数。由于及其功能函数。由于MFCMFC对对
2、Win32 Win32 APIAPI编程方式的极好地封装,使得我们编程方式的极好地封装,使得我们甚至不需要理解甚至不需要理解WindowsWindows内部编程机制内部编程机制就可以通过就可以通过 应用程序向导应用程序向导 创建相应的创建相应的应用程序框架,这些框架能满足绝大多应用程序框架,这些框架能满足绝大多数开发者的需求,并且使得我们不必添数开发者的需求,并且使得我们不必添加太多的代码就能实现最常用的程序功加太多的代码就能实现最常用的程序功能。因此,能。因此,MFCMFC是是Visual C+Visual C+中影响最中影响最深的一种编程方式,并且这个编程方式深的一种编程方式,并且这个编程
3、方式将会一直影响下去。将会一直影响下去。WindowsWindows应用程序的特点应用程序的特点 Windows之所以取得成功,主要在于它具有以下优点:直观、高效的面向对象的图形用户界面,易学易用:从某种意义上说,Windows用户界面和开发环境都是面向对象的。用户采用“选择对象-操作对象”这种方式进行工作。比如要打开一个文档,我们首先用鼠标或键盘选择该文档,然后从右键菜单中选择“打开”操作,打开该文档。这种操作方式模拟了现实世界的行为,易于理解、学习和使用。用户界面统一、友好、漂亮:Windows应用程序大多符合IBM公司提出的CUA(Common User Acess)标准,所有的程序拥有
4、相同的或相似的基本外观,包括窗口、菜单、工具条等。用户只要掌握其中一个,就不难学会其他软件,从而降低了用户培训学习的费用。丰富的设备无关的图形操作:Windows的图形设备接口(GDI)提供了丰富的图形操作函数,可以绘制出诸如线、圆、框等的几何图形,并支持各种输出设备。设备无关意味着在针式打印机上和高分辨率的显示器上都能显示出相同效果的图形。Windows程序的所有输出都是图形。GDI(GraphicsDeviceInterface):图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。GDI+和传统的GDI不同,GDI+中引入了对COM(组件对
5、象模型)技术的支持,通过COM技术,GDI+简化了对图像文件的访问(打开、保存)。GDI+是由.NET Framework中的system.drawing命名空间提供的一组类,它使开发人员可以利用Windows内置的图形功能轻松地创建图形应用程序。OpenGL(OpenGraphicsLibrary)OpenGL是个专业的3D程序接口,是一个功能强大,调用方便的底层3D图形库。多任务:Windows是一个多任务的操作环境,它允许用户同时运行多个应用程序,或在一个程序中同时做几件事情。每个程序在屏幕上占据一块矩形区域,这个区域称为窗口,窗口是可以重叠的。用户可以移动这些窗口,或在不同的应用程序之
6、间进行切换,并可以在程序之间进行手工和自动的数据交换和通信。虽然同一时刻计算机可以运行多个应用程序,但仅有一个是处于活动状态的,其标题栏呈现高亮颜色。一个活动的程序是指当前能够接收用户键盘输入的程序。丰富的用户界面对象Windows支持丰富的用户接口对象,包括:窗口、图标、菜单、对话框等等。程序员只需简单的几十行代码,就可以设计出一个非常漂亮的图形用户界面。而在DOS环境下,则需要大量的代码来完成同样的工作,而且效果也没有Windows提供的那么好。Windows Windows应用程序是事件驱动应用程序是事件驱动(或称作消息驱动或称作消息驱动)的的 传统的MS-DOS程序主要采用顺序的、关联
7、的、过程驱动的程序设计方法。一个程序是一系列预先定义好的操作序列的组合,它具有一定的开头、中间过程和结束。程序直接控制程序事件和过程的顺序。这样的程序设计方法是面向程序而不是面向用户的,交互性差,用户界面不够友好,因为它强迫用户按照某种不可更改的模式进行工作。事件驱动程序设计是一种全新的程序设计方法,它不是由事件的顺序来控制,而是由事件的发生来控制,而这种事件的发生是随机的、不确定的,并没有预定的顺序,这样就允许程序的的用户用各种合理的顺序来安排程序的流程。对于需要用户交互的应用程序来说,事件驱动的程序设计有着过程驱动方法无法替代的优点。它是一种面向用户的程序设计方法,它在程序设计过程中除了完
8、成所需功能之外,更多的考虑了用户可能的各种输入,并针对性的设计相应的处理程序。它是一种“被动”式程序设计方法,程序开始运行时,处于等待用户输入事件状态,然后取得事件并作出相应反应,处理完毕又返回并处于等待事件状态。资源共享对于DOS程序来说,它运行时独占系统的全部资源,包括显示器、内存等,在程序结束时才释放资源。而Windows是一个多任务的操作系统,各个应用程序共享系统提供的资源,常见的资源包括:设备描述表,画刷,画笔,字体,对话框控制,对话框,图标,定时器,插入符号,通信端口,电话线等。Windows要求应用程序必须以一种能允许它共享Windows资源的方式进行设计,它的基本模式是这样的:
9、1.向Windows系统请求资源;2.使用该资源;3.释放该资源给Windows以供别的程序使用。即使最有经验的Windows程序员也常常会忽略第三步。如果忽略了这一步,轻则当时不出错,但过一会儿出现程序运行出现异常情况,或干扰别的程序正常运行;重则立即死机,比如设备描述表对象没有释放时。在Windows应用程序设计中,CPU也是一种非常重要的资源,因此应用程序应当避免长时间的占用CPU资源(如一个特别长的循环);如果确实需要这样做,也应当采取一些措施,以让程序能够响应用户的输入。主存也是一个共享资源,要防止同时运行的多个应用程序因协调不好而耗尽内存资源。应用程序一般不要直接访问内存或其他硬件
10、设备,如键盘、鼠标、计数器、屏幕或串口、并口等。Windows系统要求绝对控制这些资源,以保证向所有的应用程序提供公平的不中断的运行。如果确实要访问串并口,应当使用通过Windows提供的函数来安全的访问。事件和消息事件和消息 事件事件:比较常见的例如:鼠标事件,包含鼠标移动、鼠标点击、鼠标位于窗口的位置等。而应用程序打开后,在那里静静地等待,等待各种事件发生,然后进行相应的处理,执行特定的功能。事件也可以由用户来定义,例如:某段程序处理完毕也可以作为一个事件。消息:消息:一条消息是关于发生事件的信息。例如:一个键或鼠标按钮被按下,就发生一个消息;而当松开时,另一个消息又发生了。消息的产生也不
11、仅仅来源于键盘和鼠标的,消息可由应用程序本身产生,也可由运行的其它应用程序产生,还可以由用户或Windows产生,每当事件发生时,Windows做出记录并将相应的消息分配到有关的应用程序中去。消息实际上就是一个整型值.如果你查看一下你的头文件的话(当你去调查API的工作机制的话,这是一个非常好的也是大多数人都有的习惯)你就发现下面这些东西:#defineWM_INITDIALOG0 x0110#defineWM_COMMAND0 x0111#defineWM_LBUTTONDOWN0 x0201Windows应用程序的消息来源有以下四种:应用程序的消息来源有以下四种:(1)输入消息:包括键盘和
12、鼠标的输入。这一类消息首先放在系统消息队列中,然后由Windows将它们送入应用程序消息队列中,由应用程序来处理消息。(2)控制消息:用来与Windows的控制对象,如列表框、按钮、检查框等进行双向通信。当用户在列表框中改动当前选择或改变了检查框的状态时发出此类消息。这类消息一般不经过应用程序消息队列,而是直接发送到控制对象上去。(3)系统消息:对程序化的事件或系统时钟中断作出反应。一些系统消息,象DDE消息(动态数据交换消息)要通过Windows的系统消息队列,而有的则不通过系统消息队列而直接送入应用程序的消息队列,如创建窗口消息。(4)用户消息:这是程序员自己定义并在应用程序中主动发出的,
13、一般由应用程序的某一部分内部处理。Windows操作系统包括三个内核基本元件:GDI,KERNEL,USER。其中GDI(图形设备接口)负责在屏幕上绘制像素、打印硬拷贝输出,绘制用户界面包括窗口、菜单、对话框等。系统内核KERNEL支持与操作系统密切相关的功能:如进程加载,文本切换、文件I/O,以及内存管理、线程管理等。USER为所有的用户界面对象提供支持,它用于接收和管理所有输入消息、系统消息并把它们发给相应的窗口的消息队列。消息队列是一个系统定义的内存块,用于临时存储消息;或是把消息直接发给窗口过程。每个窗口维护自己的消息队列,并从中取出消息,利用窗口函数进行处理。框图如下:windowp
14、rocedure应用程序消息队列应用程序消息队列系统消息队列系统消息队列用户产生事件,由操作系统捕捉到该事件,并用户产生事件,由操作系统捕捉到该事件,并把相应事件的消息存入系统消息队列,再把它把相应事件的消息存入系统消息队列,再把它们发到相应的窗口的消息队列中们发到相应的窗口的消息队列中 Windows是一个多任务的操作系统,也就是说,在同一时刻,在Windows中有着多个应用程序的实例正在运行,比如说这时我正在打开字处理软件Word来编写这本书的书稿,同时,还打开了Visual C+的集成开发环境Microsoft Developer Studio来调试书中的示例程序,而且,后台还在放着歌曲
15、。在这样的一个操作系统中,不可能像过去的DOS那样,由一个应用程序来享用所有的系统资源,这些资源是由Windows统一管理的。那么,特定的应用程序如何获得用户输入的信息呢?事实上,Windows时刻监视着用户的一举一动,并分析用户的动作与哪一个应用程序相关,然后,将用户的动作以消息的形式发送给该应用程序,应用程序时刻等待着消息的到来,一但发现它的消息队列中有未处理的消息,就获取并分析该消息,最后,应用程序根据消息所包含的内容采取适当的动作来响应用户所作的操作。举一个例子来说明上面的问题,假设我们编了一个程序,该程序有一个File菜单,那么,在运行该应用程序的时候,如果用户单击了File菜单,这
16、个动作将被Windows(而不是应用程序本身!)所捕获,Windows经过分析得知这个动作应该由上面所说的那个应用程序去处理,既然是这样,Windows就发送了个叫做WM_COMMAND的消息给应用程序,该消息所包含的信息告诉应用程序:“用户单击了File菜单”,应用程序得知这一消息之后,采取相应的动作来响应它,这个过程称为消息处理。Windows为每一个应用程序(确切地说是每一个线程)维护了相应的消息队列,应用程序的任务就是不停的从它的消息队列中获取消息,分析消息和处理消息,直到一条接到叫做WM_QUIT消息为止,这个过程通常是由一种叫做消息循环的程序结构来实现的。从某种角度上来看,Wind
17、ows应用程序是由一系列的消息处理代码来实现的。这和传统的过程式编程方法很不一样,编程者只能够预测用户所利用应用程序用户界面对象所进行的操作以及为这些操作编写处理代码,却不可以知道这些操作在什么时候发生或者是以什么顺序来发生,也就是说,我们不可能知道什么消息会在什么时候以什么顺序来临。下图给出了一般Windows应用程序的执行流程。Windows APIWindows API API,全称application program interface,意思是应用程序编程接口(说起API并不仅仅指windows而言,windows支持的API叫winapi)。winapi就是应用程序和windows
18、之间通讯的一个编程界面。windows提供了上千个API函数,以方便程序员来编写应用程序。做数据库管理系统是很少和API打交道的,像PB、VB等。总之,进行系统编程,API是必不可少的。API是每个VC高手的必过的一关。Windows API具有两种基本类型:Win16 API和Win32 API。两者在很多方面非常相像,但是Win32 API除了几乎包括了Win16 API中的所有内容以外,还包括很多的其它内容。Windows API依靠三个主要的核心组件提供Windows的大部分函数,在Win16和Win32中,它们具有不同的名称,如表3.1 Win16和Win32的核心组件:SDKSDK
19、编程编程Win16 APIWin16 APIWin32 APIWin32 API说明说明USER.EXEUSER.EXEUSER32.DLLUSER32.DLL负责窗口的管理,包括负责窗口的管理,包括消息、菜单、光标、通消息、菜单、光标、通信、计时器和其它与控信、计时器和其它与控制窗口显示制窗口显示GDI.EXEGDI.EXEGDI32.DLLGDI32.DLL提供图形设备接口,管提供图形设备接口,管理用户界面和图形绘制,理用户界面和图形绘制,包括包括WindowsWindows元文件、元文件、位图、设备描述表和字位图、设备描述表和字体等体等KRNL386.EXEKRNL386.EXEKERN
20、EL32.DLLKERNEL32.DLL处理存储器低层功能、处理存储器低层功能、任务和资源管理等任务和资源管理等WindowsWindows核心服务核心服务 虽然Win16 API组件带有.EXE的扩展名,但是它们事实都是动态链接库(.DLL),不能单独运行。其它一些非核心的Windows API由其它组件所提供的DLL来实现,这些组件包括通用对话框、打印、文件压缩、版本控制以及多媒体支持等。Windows SDK Windows SDK大致说来Windows编程有两种方法:1.1.WindwosWindwos C C方式(方式(SDKSDK)2.C+2.C+方式方式:即对即对SDKSDK函数
21、进行包装,如函数进行包装,如VCVC的的MFC,BCBMFC,BCB的的OWLOWL等,如果要深入等,如果要深入 下去,还是要熟下去,还是要熟悉悉SDKSDK。两种方法有哪些区别呢:SDK编程就是直接调用windows的API进行编程,但是有上千个API组成(win95的API有两千多个),这种数目太大了,对于编程显然不利。而MFC把这些API封闭起来,共有一百多个类组成。一般只需20多个windows类和另外20多个通用的非windows类就可“干活”了,这一改变无疑是有很大好处的。尽管MFC如此方便,但是要学VC,直接去学MFC却是不明智的选择。只有在熟悉了MFC的运行机制的情况下,才有可
22、能深入下去。那些如多少天精通什么什么的书籍其实讲的全是些如怎么使用VC这种工具的话题,学来学去学会了怎么会使用VC这种工具,而不能深入MFC编程。WinSDKWinSDK程序设计程序设计 就是API方式的windows程序设计。SDK,全称Software Developers Kit,意思是软件开发工具箱。它是在windows程序设计早期,程序员进行windows程序设计所必须购买的一个软件包。开始进行WinSDK编程用C语言最好,可以撇开C+的特性专心熟悉一下Win32编程的思路以及了解windows的消息运行机制。等把这些有所了解后,慢慢转向C+和MFC编程。不过我的观点是WinSDK编
23、程永远要慢慢进行下去,直接接触底层代码对MFC源码的理解是有很大好处的。该工具包的最新版本就是我们正在使用的Win32 SDK,在安装了Visual C+的同时,Win32 SDK也安装到你的计算机上了。尽管MFC提供了对Win32 API的比较完整的封装,但是,在某些情况下,我们更倾向于直接调用Win32 API,因为这有时候可以获得更高的效率,并且有着更大的自由度。而且,使用MFC编写的新风格的Windows应用程序的工作方式基本上与使用SDK编写的同一程序一样,它们往往有着很多的共同之处,只是使用MFC更加的方便,因为它隐藏了大量的复杂性。前面提到过,面向对象的编程方式是当前最流行的程序
24、设计方法,但是,Win32 API本身却是基于C语言的过程式编程的,SDK和MFC的最主要的不同之处也就是以C与C+之间的差别,使用MFC进行Windows应用程序设计需要面向对象的编程思想和方法。一个简单的一个简单的SDKSDK应用程序应用程序 for example:第五讲第五讲/hello_sdk.sln(1)单击开始页面中的新建项目,或者打开文件菜单中的新建,选择项目命令,都将弹出新建项目对话框。(2)在左侧的项目类型窗格中,选中Visual C+项目。在右侧的模板窗格中,拖动窗格右侧的滚动条显示其他模板,然后选中Win32 项目。(3)在名称文本框中,输入项目名称“hello_sdk
25、,单击确定按钮,弹出Win32 应用程序向导对话框。(4)单击左侧的应用程序设置。选中应用程序类型中的Windows 应用程序,在附加选项中选中空项目,单击完成按钮。几个要点理解:几个要点理解:1.1.Windows数据类型数据类型在下表中列出的数据类型许多并不是标准C/C+数据类型,而是相当特殊的Windows头文件中定义的数据类型。例如,COLORREF是一个Windows数据类型,用于存放24位RGB颜色值;BOOL是存储TRUE/FALSE值的一个布尔数据类型;而DWORD是一个32位无符号整数。过一段时间,你会想了解C/C+标准数据类型一样,掌握这些数据类型。Windows中所用的中
26、所用的数据类型数据类型对应的基本数对应的基本数据类型据类型说明说明BOOLint布尔值布尔值BSTRunsignedshort*32位字符指针位字符指针BYTEunsignedchar8位无符号整数位无符号整数COLORREFunsignedlong用作颜色值的用作颜色值的3232位值位值DWORDunsignedlong32位无符号整数,段位无符号整数,段地址和相关的偏移地地址和相关的偏移地址址LONGlong32位带符号整数位带符号整数LPARAMlong作为参数传递给窗口作为参数传递给窗口过程或回调函数的过程或回调函数的3232位值位值LPCSTRconstchar*指向字符串常量的指向
27、字符串常量的3232位指针位指针LPSTRchar*指向字符串的指向字符串的3232位指位指针针LPCTSTRconstchar*指向可移植的指向可移植的UnicodeUnicode和和DBCSDBCS字符串常量的字符串常量的3232位指针位指针LPTSTRchar*指向可移植为指向可移植为UnicodeUnicode和和DBCSDBCS字符串的字符串的3232位位指针指针LPVOIDvoid*指向未定义类型的指向未定义类型的3232位指针位指针LRESULTlong来自窗口过程或回调来自窗口过程或回调函数的函数的3232位返回值位返回值UINTunsignedint32位无符号整数位无符号整
28、数WNDPROClong(_stdcall*)(void*,unsignedint,unsignedint,long)指向窗口过程的指向窗口过程的3232位位指针指针WORDunsignedshort 16位无符号整数位无符号整数WPARAMunsignedint当作参数传递给窗口当作参数传递给窗口过程或回调函数的过程或回调函数的3232位值位值2.2.句柄句柄(handle)WONDOWS用句柄来标识被应用程序所建立或使用的对象,在WINDOWS编程中会用到大量的句柄,比如:HINSTANCE(实例句柄),HBITMAP(位图句柄),HDC(设备描述表句柄),HICON(图标句柄)等等。应用
29、程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。在WINDOWS编程中会用到大量的句柄。句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果
30、地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。句柄地址(稳定)记载着对象在内存中的地址对象在内存中的地址(不稳定)实际对象。但是,必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄
31、还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。当然,句柄可能在其内部结构中记录了很多信息(如权限、有无信号等),不仅仅是对象在内存中的地址.Windows公用句柄类型句柄类型说明HBITMAP保存位图信息的内存域的句柄HBRUSH画刷句柄HCTR子窗口控件句柄HCURSOR鼠标光标句柄HDC设备描述表句柄HDLG对话框句柄HFONT字体句柄HICON图标句柄HINSTANCE应用程序的实例句柄HMENU菜单句柄HMODULE模块句柄HP
32、ALETTE颜色调色板句柄HPEN在设备上画图时用于指明线型的笔的句柄HRGN剪贴区域句柄HTASK独立于已执行任务的句柄HWND窗口句柄实例句柄实例句柄(hinstancehinstance)_)_最简单的理解可以用下面的例子来说明:比如说已经在Windows中打开了一个“写字板”,现在你需要从另一篇文章里复制一部分内容到你正在写的这篇文章中,那么,你可以再打开一个“写字板”(注意写字板不是一个多文档应用程序,不能像在Word中那样打开多个不同的文件),然后从该写字板中复制文件的内容到在前一个写字板内打开的文章中。这里,我们多次运行了同一个应用程序,在这个例子中,我们将所打开的两个写字板叫做
33、该应用程序的两个实例。代码分析代码分析:Windows程序则至少两个主程序,一个是WinMain():intint WINAPI WINAPI WinMainWinMain(HINSTANCE HINSTANCE hInstancehInstance,/handle to current instance/handle to current instance HINSTANCE HINSTANCE hPrevInstancehPrevInstance,/handle to previous instance/handle to previous instance LPSTR LPSTR lpC
34、mdLinelpCmdLine,/command line/command line int nCmdShow int nCmdShow/show state/show state););另一个是窗口过程函数WndProc,它的函数原型为:long FAR PASCAL long FAR PASCAL WndProcWndProc(HWND(HWND hWndhWnd,WORD message,WORD,WORD message,WORD wParamwParam,LONG,LONG lParamlParam););Windows应用程序的编程就围绕这两个部份进行的。其中WinMain函数为应
35、用程序的入口点,它的名字一定要是WinMain。窗口过程函数WndProcLRESULT CALLBACK LRESULT CALLBACK WndProcWndProc(HWND,UINT,WPARAM,LPARAM);(HWND,UINT,WPARAM,LPARAM);在Windows中,用户产生事件,Windows把发生的输入事件转换成输入消息放到消息队列中,而消息循环将它们发送到相应的窗口过程函数,真正的处理是在窗口过程函数中执行的,在Windows中就使用了回调函数来进行这种通信。应用程序通过与Windows通信合作完成指定的操作,而承担这项通信任务的API函数就是Windows的相
36、应窗口函数WndProc。应用程序不直接调用任何窗口函数,而是等待Windows调用窗口函数,请求完成任务或返回信息。为保证Windows调用这个窗口函数,这个函数必须先向Windows登记,然后在Windows实施相应操作时回调,所以窗口函数又称为回调函数。WndProc是一个主回调函数,Windows至少有一个回调函数。每个窗口必须有一个窗口过程与之对应,且Windows直接调用本函数,因此,窗口函数必须采用FAR PASCAL调用约定。回调函数WndProc在哪里定义的呢,请看这个语句:wc.lpfnWndProc=WndProc;注册窗口类注册窗口类(1)(1)第一个参数第一个参数:成
37、员成员stylestyle控制窗口的某些重要特性,在控制窗口的某些重要特性,在WINDOWS.HWINDOWS.H中定义了一些前缀为中定义了一些前缀为CSCS的常量,在程序中可组合使用这些的常量,在程序中可组合使用这些常量常量.也可把也可把sytlesytle设为设为0.0.本程序中为本程序中为wcwc.style=CS_HREDRAW|CS_VREDRAW.style=CS_HREDRAW|CS_VREDRAW,它表示当窗口的纵横坐标发生变化时要重画整它表示当窗口的纵横坐标发生变化时要重画整个窗口。你看:无论你怎样拉动窗口的大小,那行字都会停留在窗口的正中部,而假如把这个参数设为个窗口。你看
38、:无论你怎样拉动窗口的大小,那行字都会停留在窗口的正中部,而假如把这个参数设为0 0的话,当改动窗口的话,当改动窗口的大小时,那行字则不一定处于中部了。的大小时,那行字则不一定处于中部了。(2)(2)第二个参数第二个参数:lpfnWndProclpfnWndProc包括一个指向该窗口类的消息处理函数的指针,此函数称为窗口过程函数。它将接收包括一个指向该窗口类的消息处理函数的指针,此函数称为窗口过程函数。它将接收WindowsWindows发发送给窗口的消息,并执行相应的任务。送给窗口的消息,并执行相应的任务。(3)(3)第三第三,四个参数四个参数:cbWndExtracbWndExtra域指定
39、用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗域指定用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。一般来讲,你只要把它们设为口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。一般来讲,你只要把它们设为0 0就行了就行了,不必过多不必过多考虑。考虑。(4)(4)第五个参数第五个参数:hInstancehInstance域标识应用程序的实例域标识应用程序的实例hInstancehInstance,当然,实例名是可以改变的。当然,实例名是可以改变的。wcwc.hI
40、nstancehInstance=hInstancehInstance;这这一成员可使一成员可使WindowsWindows连接到正确的程序。连接到正确的程序。(5)(5)第六个参数第六个参数:成员成员hIconhIcon被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用以表示程序仍驻留在内存中。以表示程序仍驻留在内存中。WindowsWindows提供了一些默认图标,我们也可定义自己的图标,提供了一些默认图标,我们也可定义自己的图标,VCVC里面专有一个制作图标的工具。里面专
41、有一个制作图标的工具。(6)(6)第七个参数第七个参数:hCursorhCursor域定义该窗口产生的光标形状。域定义该窗口产生的光标形状。LoadCursorLoadCursor可返回固有光标句柄或者应用程序定义的光标句柄。可返回固有光标句柄或者应用程序定义的光标句柄。IDC_ARROWIDC_ARROW表示箭头光标表示箭头光标.(7)(7)第八个参数第八个参数:wcwc.hbrBackgroundhbrBackground域决定域决定WindowsWindows用于着色窗口背景的刷子颜色,函数用于着色窗口背景的刷子颜色,函数GetStockObjectGetStockObject返回窗口的
42、颜色,本返回窗口的颜色,本程序中返回的是白色,你也可以把它改变为红色等其他颜色程序中返回的是白色,你也可以把它改变为红色等其他颜色.试试看试试看(8)(8)第九个参数第九个参数:lpszMenuNamelpszMenuName用来指定菜单名,本程序中没有定义菜单,所以为用来指定菜单名,本程序中没有定义菜单,所以为NULLNULL。(9)(9)第十个参数第十个参数:lpszClassNamelpszClassName指定了本窗口的类名。指定了本窗口的类名。当对当对WNDCLASSWNDCLASS结构域一一赋值后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的结构域一一赋值
43、后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的APIAPI函数函数是是RegisterClassRegisterClass,注册失败的话,就会出现一个对话框如程序所示,函数注册失败的话,就会出现一个对话框如程序所示,函数RegisterClassRegisterClass返回返回0 0值值,也只能返回也只能返回0 0值,因为注册值,因为注册不成功,程序已经不能再进行下去了。不成功,程序已经不能再进行下去了。创建消息循环主窗口显示出来了,WinMain就开始处理消息了,怎么做的呢?Windows为每个正在运行的应用程序都保持一个消息队列。当你按下鼠标或者键盘时,Win
44、dows并不是把这个输入事件直接送给应用程序,而是将输入的事件先翻译成一个消息,然后把这个消息放入到这个应用程序的消息队列中去。应用程序又是怎么来接收这个消息呢?这就讲讲消息循环了。应用程序的WinMain函数通过执行一段代码从她的队列中来检索Windows送往她的消息。然后WinMain就把这些消息分配给相应的窗口函数以便处理它们,这段代码是一段循环代码,故称为“消息循环”。消息循环以GetMessage调用开始,它从消息队列中取出一个消息:GetMessage(&msg,NULL,0,0),第一个参数是要接收消息的MSG结构的地址,第二个参数表示窗口句柄,NULL则表示要获取该应用程序创建
45、的所有窗口的消息;第三,四参数指定消息范围。后面三个参数被设置为默认值,这就是说你打算接收发送到属于这个应用程序的任何一个窗口的所有消息。在接收到除WM_QUIT之外的任何一个消息后,GetMessage()都返回TRUE。如果GetMessage收到一个WM_QUIT消息,则返回FALSE,如收到其他消息,则返回TRUE。因此,在接收到WM_QUIT之前,带有GetMessage()的消息循环可以一直循环下去。只有当收到的消息是WM_QUIT时,GetMessage才返回FALSE,结束消息循环,从而终止应用程序。均为NULL时就表示获取所有消息。消息用GetMessage读入后(注意这个消
46、息可不是WM_QUIT消息),它首先要经过函数TranslateMessage()进行翻译,这个函数会转换成一些键盘消息,它检索匹配的WM_KEYDOWN和WM_KEYUP消息,并为窗口产生相应的ASCII字符消息(WM_CHAR),它包含指定键的ANSI字符.但对大多数消息来说它并不起什么作用,所以现在没有必要考虑它。下一个函数调用DispatchMessage()要求Windows将消息传送给在MSG结构中为窗口所指定的窗口过程。我们在讲到登记窗口类时曾提到过,登记窗口类时,我们曾指定Windows把函数WindosProc作为咱们这个窗口的窗口过程(就是指处理这个消息的东东)。就是说,W
47、indows会调用函数WindowsProc()来处理这个消息。在WindowProc()处理完消息后,代码又循环到开始去接收另一个消息,这样就完成了一个消息循环。终止应用程序终止应用程序:WindowsWindows是一种非剥夺式多任务操作系统。只有当前的应用程序交出是一种非剥夺式多任务操作系统。只有当前的应用程序交出CPUCPU控制权后,控制权后,WindowsWindows才才能把控制权交给其他应用程序。当能把控制权交给其他应用程序。当GetMessageGetMessage函数找不到等待应用程序处理的消息时,自动函数找不到等待应用程序处理的消息时,自动交出控制权,交出控制权,Windo
48、wsWindows把把CPUCPU的控制权交给其他等待控制权的应用程序。由于每个应用程序都的控制权交给其他等待控制权的应用程序。由于每个应用程序都有一个消息循环,这种隐式交出控制权的方式保证各个应用程序共享控制权。一旦发往该应有一个消息循环,这种隐式交出控制权的方式保证各个应用程序共享控制权。一旦发往该应用程序的消息到达应用程序队列,即开始执行用程序的消息到达应用程序队列,即开始执行GetMessageGetMessage语句的下一条语句。语句的下一条语句。当当WinMainWinMain函数把控制返回到函数把控制返回到WindowsWindows时,应用程序就终止了。应用程序的启动消息循环前
49、要时,应用程序就终止了。应用程序的启动消息循环前要检查引导出消息循环的每一步,以确保每个窗口已注册,每个窗口都已创建。如存在一个错检查引导出消息循环的每一步,以确保每个窗口已注册,每个窗口都已创建。如存在一个错误,应用程序应返回控制权,并显示一条消息。误,应用程序应返回控制权,并显示一条消息。但是,一旦但是,一旦WinMainWinMain函数进入消息循环,终止应用程序的唯一办法就是使用函数进入消息循环,终止应用程序的唯一办法就是使用PostQuitMessagePostQuitMessage把消息把消息WM_QUITWM_QUIT发送到应用程序队列。当发送到应用程序队列。当GetMessag
50、eGetMessage函数检索到函数检索到WM_QUITWM_QUIT消息,它就返回消息,它就返回NULLNULL,并退出消息外循环。通常,当主窗口正在删除时并退出消息外循环。通常,当主窗口正在删除时(即窗口已接收到一条即窗口已接收到一条WM_DESTROYWM_DESTROY消息消息),),应应用程序主窗口的窗口函数就发送一条用程序主窗口的窗口函数就发送一条WM_QUITWM_QUIT消息。消息。return msg.return msg.wParamwParam;/;/表示从表示从PostQuitMessagePostQuitMessage返回的值返回的值例如:当例如:当WindowsWi