920 likes | 1.12k Views
第一章 Windows 编程基础知识. 1.1 Windows 操作系统的特点 1 直观的图形化用户界面 Windows 应用程序的外观是由诸如 窗口 、 菜单 、 工具栏 、 状态 栏 、 滚动条 、 对话框 等标准图形元素构成的。程序运行中的人 机交互操作也都是通过这些标准图形元素进行的。我们将这样 的用户界面称为图形化用户界面 GUI ( G raphics U ser I nterface )。 GUI 使得应用程序的用户界面统一、友好、美观。. 2 丰富的设备无关操作 Window 程序的输出显示均为图形操作(包括文本操作)。各
E N D
1.1 Windows 操作系统的特点 1 直观的图形化用户界面 Windows 应用程序的外观是由诸如窗口、菜单、工具栏、状态 栏、滚动条、对话框等标准图形元素构成的。程序运行中的人 机交互操作也都是通过这些标准图形元素进行的。我们将这样 的用户界面称为图形化用户界面 GUI(Graphics User Interface)。 GUI 使得应用程序的用户界面统一、友好、美观。
2 丰富的设备无关操作 Window程序的输出显示均为图形操作(包括文本操作)。各 类复杂的图形操作都是通过与物理设备无关的图形设备接口GDI (Graphics Device Interface)完成的。每个图形操作都是在一个特 定的图形设备上下文(Device Context)中完成的。也就是说,通 过设备上下文句柄,能够调用图形设备接口 GDI所提供的相应 图形操作进行格式统一而具有特定功能的图形绘制操作,而这 些图形操作又可以通过对应的物理图设备驱动的支持,在指定 的设备上实现相应的图形输出。下图形象地示意了这种 GDI图 形接口的实现机制:
显示器驱动 打印机驱动 绘图仪驱动 GDI 虚拟设备
3 完善的多任务运行环境 Windows是一个多任务的操作系统。这种多任务表现在多个 不同进程(包括同一程序的多个进程实例)的同时运行和同一 进程中的多个线程的同时运行。这些同时运行的多任务对系统 资源的共享表现在: CPU:通过系统分时实现多任务共享同一 CPU。 屏幕:通过可以重叠或平铺分布的窗口实现多个任务的视窗可 以共享同一屏幕,用户可以通过切换不同任务的窗口为活 动窗口,在不同任务之间进行切换。 内存:通过虚拟内存管理实现多任务共享有限的内存资源。多 任务之间可以进行手工和自动的数据交换和通信。
其中 Windows虚拟内存管理的实现如下: ⑴ 进程和内存空间 下面给出的图是在 Windows 95平台上,执行同一个 EXE 文 件的两个不同进程时的虚拟内存映射图。
0xFFFFFFFF 共享内存空间 0xC0000000 0x80000000 0x5F400000 0x10000000 堆 堆 堆 堆栈 堆栈 可读/写全局内存 可读/写全局内存 0x00400000 进程A 硬盘 进程B Windows 系统代码 Windows DLL 内存映射文件 MFC42.DLL 用户.DLL 交换文件 EXE文件
对于每个进程来说,只有低端的 2GB(0-0x7FFFFFFF) 的 地址空间是真正属于进程私有的。其中最低端的 4MB内存空间 是禁止访问的。进程运行期间所需要的堆栈、堆和可读/写的全 局内存以及应用程序的 EXE 文件和DLL文件都被映射到这 2GB 空间内。而高端的 2GB空间对所有的进程都是一样的,在这一 区间存放着所有进程共享的 Windows核心执行过程,虚拟设备 驱动程序(VxD)和文件系统代码以及一些重要的表(如映射页 表)都被映射到最高端1GB(0xC0000000 - 0xFFFFFFFF)空间中。 Windows DLL和内存映射文件在 0x80000000 - 0xBFFFFFFF 的内存 空间中。
由于低端的 2GB内存空间分配给特定的进程,所以一个进 程想要改变另一个进程的堆栈、全局内存或者堆空间的内容是 不可能的。 EXE和 DLL代码存放空间都有只读标记,因此,它们被映射 到多个进程是没有问题的。然而在最高端的 1GB空间有重要的 Windows可读数据,因此,这部分内存很容易受到错误程序的攻 击,例如毁坏系统表。在 0x80000000 - 0xBFFFFFFF地址空间中 存放的一个进程的映射文件也可能被另一个进程破坏。
在 Windows NT 中这些问题不会发生,因为在 Windows NT 中,进程只允许访问低端的 2GB空间,并且这 2GB的最高端和 最低端的 64KB空间是不允许访问的。同时高端的 2GB空间中 所存放的内容完全受保护。这就是为何提倡使用 Windows NT的 原因之一( Windows 2000 和 Windows XP 有类似的安全机制)。 ⑵ 虚拟内存如何工作 ① 为什麽要使用虚拟镜像技术 • 计算机不可能有数百个 GB的 RAM(物理内存)和数百个 GB的磁盘空间能满足多进程(每个进程 4GB)的需要。 • 每个进程的 4GB空间不会全部使用,更不会同时使用。
32位线性地址 位 31--22 位 21--12 位 11--0 每个进程拥有一个页表目录,它可以保存1024个页表地址 每个页表可保存1024个虚拟内存页地址 4096字节 32位地址 页表地址 标记 32位地址 页表地址 标记 20位 12位 20位 12位 CR3寄存器 Windows在CR3中为当前进程提供一个页表目录地址 ② 如何实现虚拟镜像技术
• 32 位线性地址分三段,页表目录、页表和页内偏移量。 • 每页 4KB空间。 • 页以 4KB 为边界,即页的首地址必须是 4KB 的整倍数。 每个进程可以获得的虚拟内存空间为 4GB,每一个物理 地址的形成可以解析如下: 页表地址 = 页表目录地址+ 偏移量(第 22 - 31位),共 有1K 个页表。 页地址 = 页表地址+ 偏移量(地址第 12 - 21位),共有 1K*1K = 1M页。 物理地址 = 页地址 + 偏移量(地址第 0 - 11位),共有 1M*4KB = 4GB内存单元
• 每个页表入口都包含存在位(表示页是否在物理 RAM 中) 和读/写位(表示页中内容是否可读/写或只读)。 当需要访问此页内容时,根据“存在”位确定是否需要将此 页的内容从磁盘读入到此物理页中。如果页中内容有一段 时间未被访问,则根据虚拟管理的优化算法确定是否将页 中内容交换到磁盘中或直接放弃,使物理页空间可以被新 进程的页使用。在收回页面使用时,根据页的“读/写”位来 确定是将页中内容交换到磁盘中(例如,进程中所有可读 /写数据),或直接放弃(例如,程序 EXE代码和 DLL代 码,进程中的常量)。
③ 用户可以使用的内存操作函数 • 使用VirtualAlloc 进行内存的保留和占用,该函数的原型: LPVOID VirtualAlloc( LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect ) • 使用 VirtualFree 收回 VirtualAlloc 保留和占用的内存空间。 VirtualFree 的原型: BOOL VirtualFree( LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType ); • 使用GlobalAlloc 函数在Windows运行时堆中分配空间。 HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes); • 使用GlobalLock锁定GlobalAlloc 分配的内存空间一次, 并获取操作句柄。每锁定一次LockCount+1。 LPVOID GlobalLock(HGLOBALhMem);
• 使用GlobalUnlock 将内存空间解锁一次,LockCount–1, 当LockCount为0时,所分配的内存空间不再被锁定。 BOOL GlobalUnlock(HGLOBALhMem); • 未锁定的内存地址(句柄)可以用GlobalFree 函数释放。 HGLOBAL GlobalFree(HGLOBALhMem ); • 使用new分配内存空间。 • 使用delete释放由new 分配的内存空间。 • 内存映射文件:将一个地址范围直接映射到相应的文件。 当进程访问相应的内存页时,系统将分配 RAM,并从磁盘 中读入数据或将内存中数据写入磁盘,它可以用于进程间 共享。
•访问资源:资源是包含在 EXE 和 DLL代码中的,因此会 占用虚拟内存空间,而且这些空间在进程的生存期内是 不会被改变的,这就使得我们很容易读取一个资源。获 取资源的函数原型: HGLOBAL LoadResource( HMODULE hModule, HRSRC hResInfo); 参数: hModule— 包含所取资源的模块句柄,NULL 表示从进程 中取资源。 hResInfo— 所取资源的句柄。 返回一个全局内存句柄HGLOBAL 可以安全地把它当作访 问存放资源的内存空间的索引。例如:
LPVOID lpvResource = (LPVOID)::LoadResource ( NULL, ::FindResource ( NULL, MAKEINTRESOURCE(IDB_REDBLOCK), RT_BITMAP )); 其中FindResource用于确定一个指定的资源位置,其原型: HRSRC FindResource( HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType ); 参数: hModule — 包含所取资源的模块句柄,NULL 表示从进程中 取资源。
lpName— 所取资源的名字串。本例中是使用宏定义 MAKEINTRESOURCE 将资源标识 IDB_REDBLOCK 转换为资源名。 pType — 所取资源的类型。本例中使用的 RT_BITMAP表示 所取资源是一个位图资源。
4 灵活的消息处理机制 ⑴ 队列化消息输入 Windows 操作系统将应用程序控制运行所需要各类信息以消 息的形式放在一个消息队列中,这个队列由操作系统管理。应 用程序只通过读取消息队列中的不同消息控制运行。 Windows 操作系统有一个系统消息队列,每个应用程序有一 个自己的消息队列,应用程序的消息来源: ①输入消息:如键盘、鼠标输入。这类消息通过系统消息 队列被送入应用程序消息队列。
②控件消息:用于与 Windows 的控件对象进行双向通信, 实现控件状态的变化。这类消息不通过系统消息队列, 可以通过应用程序消息队列,也可以直接发送到控件对 象上。 ③系统消息:由系统管理事件(例如系统时钟)引起的消 息。这类消息中有些要通过系统消息队列送到应用程序 消息队列,如 DDE(Dynamic Data Exchange)消息;而另 一些消息直接送入应用程序消息队列,如创建窗口消息。 ④用户消息:由程序员自己定义在应用程序中发出,并在 应用程序中响应处理的消息。这类消被直接送入应用程 序消息队列。
⑵支持队列特征的消息驱动模型 Windows 操作系统主要包括三个基本内核元件: ①GDI(Graphics Device Interface):负责虚拟图形设备的操 作,例如,屏幕绘图和打印。 ②KERNEL:支持与操作系统密切相关的功能(如进程加 载,文本切换,文件I/O,内存管理线程管理等)。 ③USER:为所有的用户界面对象提供接收和管理所有输入 消息、系统消息,并把它们发给相应窗口的消息队列。
⑶事件驱动的程序设计 MS-DOS应用程序主要是采用顺序的、关联的、过程驱动的 程序设计方法。因此,过程的执行顺序是由程序直接控制,并 强制用户以某种不可更改的模式进行工作,交互性差。 Windows应用程序则是采用了由事件发生来控制程序运行逻 辑的设计方法,由于事件发生是随机的,没有预定的顺序,所 以用户就可以按照各种需要的、合理的顺序来安排程序的流程。 每个事件发生都会在对应的队列中放入一条消息。程序开始运 行后,总是从消息队列中读取消息等待事件的发生,并根据消 息做出相应的响应后,返回等待事件发生的状态,直至响应了 程序退出消息导致程序运行结束退出。
⑷ 支持应用程序间数据交换 Windows支持应用程序间通过以下途径进行数据交换: ① 动态数据交换 DDE(Dynamic Data Exchange), ② 剪切板(Clipboard), ③ 对象链接和嵌入 OLE(Object Linked and Embeded), ④组件对象模型 COM(Component Object Model)和分布式组 件对象模型 DCOM(Distributed Component Object Model)。
5简便的动态链接库(DLL)应用 库是为应用程序提供各种功能和资源的最重要的途径,其中 动态链接库对于支持多任务的功能和资源共享和提高内存的使 用效率更为有效。Windows 平台为动态链接库的创建、安装和调 用提供了有效的支持,使得动态链接库的应用更加简便、可 行。所以动态链接库的开发和应用成为应用程序开发的重要手 段之一。
1.2Windows应用程序的特点 1事件驱动方式的程序设计模式 这种程序是由许多完成特定功能的子流程组成,在程序启动 运行之后,没有一个固定的执行流程,而是由用户的操作的结 果(事件)确定(驱动)子流程的执行,包括程序的结束。 2窗口程序设计模式 Windows 应用程序的基本单位不是过程和函数,而是窗口。 Windows 应用程序一般都具有标准的窗口界面风格。这个具有 标准风格的程序窗口界面都是由一系列的具有标准风格的界面 对象元素(如:窗口、图标、标题栏、菜单、工具栏、滚动 条、状态栏、对话框、控件、消息框等)组合而成的,例如 下图就是一个典型 Windows 程序的窗口界面。
3面向对象的程序设计模式 Windows 应用程序符合典型的面向对象结构的程序。程序为 用户提供的所有可视操作界面在程序内部都可视为一个 Windows 对象,用户对这些可视对象的操作通过事件驱动模式触发相应 Windows 对象的可调用方法。 Windows 程序的执行过程本身就是窗口和其他对象频繁创建、 处理和消亡的过程。程序执行过程中的消息发送可以理解为一 个窗口对象向别的窗口对象请求对象服务的过程。因此,用面 向对象的方法进行 Windows 程序设计与开发是极其方便、合理 的。
为了便于设计创建具有风格一致的窗口界面,微软公司在为了便于设计创建具有风格一致的窗口界面,微软公司在 Win32 函数库和 C++ 类库中为创建和操作上述标准界面元素提 供了大量的函数和 C++ 类。 学习和掌握有关这些标准界面元素的描述、创建的数据结 构和程序结构、C++ 类及其关系,是创建一个 Windows 程序的重 要基础之一,对于理解这些标准界面元素封装在类库中的类的 工作原理也是十分必要的,同时也有助于创建自己特殊风格的 界面元素以适应特定程序所需要的特定风格的界面。
4 资源共享 MS-DOS是单任务操作系统,DOS应用程序在运行时独占系 统的全部资源,如显示器、内存,在程序结束时才释放资源。 Windows 是一个多任务的操作系统,同时运行的各个应用程 序必须共享系统为程序运行提供的资源。系统资源是有限的, 如果使用资源的应用程序在资源使用完毕后不释放,就会造成 系统资源的枯竭,从而导致程序的运行异常,或干扰其他程序 的运行,甚至导致死机。因此 Windows 应用程序共享资源的基 本模式如下: ·向 Windows系统请求资源;
·使用资源; ·释放资源给 Windows,以供别的程序使用。 对于内存或其他硬件设备(键盘、鼠标、计数器、屏幕、 串/并接口等) 资源,一般不允许应用程序直接管理和访问, 而由 Windows 系统控制,以便向所有的应用程序提供公平的资 源,保证不中断的运行。如果应用程序确实需要对某些硬件进 行直接访问,则应当通过 Windows提供的特定 API函数实现安全 的访问。
5 程序和资源分开 在 DOS 程序中,界面设计编码工作和功能设计编码都是在 源程序中完成的。 在 Windows 应用程序中,实现界面的可视对象(如菜单、对 话框、位图等)都被从源程序中分离出来,放在资源文件(.rc) 中,并通过资源编译器将这些资源编译后,再链接到应用程序 的可执行文件或动态链接库文件中。程序与资源分离的优点: ⑴ 降低内存需求:资源可以不随着应用程序一起全部装入内 存,只有当这些资源被使用时才被装入自己的数据段,并不 驻留在应用程序的数据段;当内存紧张时,可废弃这些资源 (从内存中退出),待使用时再次自动装入。
⑵ 便于统一管理和重复利用 ⑶ 应用程序与界面有一定的独立性,有利于软件的国际化
1.3Win32 程序结构 创建 Windows程序的方法有多种,最常用的方法是选择使用 WindowsAPI函数编程或 MFC编程。其中使用 MFC是完全遵照 面向对象程序设计的编程方法,是本课程的学习重点。而使用 Windows API编程对于理解 Windows程序的特点和运行机制更为 直观,因此,对于初学者首先从 Windows API编程入手是十分 必要的。 使用 Windows API编写的典型的 Windows应用程序是由主函 数和窗口函数两个基本部分组成:
1Windows 应用程序的主函数 主函数是 Windows 应用程序的入口,相当于控制台应用程序 中的 main函数。主函数名由系统确定,不允许改变。典型的主 函数中一般包括: ⑴定义主窗口类结构变量,并初始化; ⑵使用已经初始化的窗口类结构变量注册主窗口类别; ⑶创建已经成功注册的主窗口; ⑷显示并更新主窗口; ⑸启动消息循环,不断地接收消息,并分发到相应的窗口函数 去判断处理,直至收到关闭主窗口的消息,退出消息循环、 结束程序执行。
2窗口函数 窗口函数是由用户定义,由系统调用的回调函数。它的用途 是处理窗口消息,以完成程序需求的各种特定的功能。 在 Windows应用程序的运行过程中,通常总是先创建一个主 窗口,然后根据执行功能的需要,可能会有子窗口的创建和撤 消(如用于交互操作的对话框的创建和撤消)。每个窗口都应 有一个对应的窗口函数,用于处理对应窗口消息的响应操作, 因此,在一个 Windows应用程序中通常会有多个窗口函数,但 主窗口函数只有一个,换言之,Windows应用程序至少应有一个 主窗口函数。 主窗口函数必须在创建前通过主窗口类变量进行注册,而子 窗口函数一般是在主窗口函数中被注册、创建和撤消的。
1.3.1 定义窗口类的结构 窗口是一个具有标准风格的界面对象元素,它使用一个数 据结构来描述窗口样式、窗口消息处理函数、程序句柄、图标、 光标、背景刷、菜单以及描述本窗口类型结构的名称。根据这 个数据结构内容的描述,就可以创建一个具体的窗口。这个数 据结构的类型名为 WNDCLASS,定义如下:
typedef struct _WNDCLASS { UINT style; // 窗口格式 WNDPROC lpfnWndProc; // 窗口函数指针 int cbClsExtra; // 窗口类结构变量后额外分配的字节数 int cbWndExtra; // 窗口实例后额外分配的字节数 HANDLE hInstance; // 窗口实例句柄 HICON hIcon; // 窗口图标句柄 HCURSOR hCursor; // 鼠标位置光标句柄 HBRUSH hbrBackground; // 窗口背景画刷句柄 LPCTSTR lpszMenuName; // 窗口菜单名字串指针 LPCTSTR lpszClassName; // 窗口类名字串指针 } WNDCLASS;
定义一个窗口类别结构变量,并初始化,例如:定义一个窗口类别结构变量,并初始化,例如: WNDCLASSwndclass; wndclass.style = CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackgound = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = “MyMenu”; wndclass.lpszClassName = “MyWndClass”;
扩展的窗口数据结构为 WNDCLASSEX,其定义如下: typedef struct _WNDCLASSEX { UINT cbSize; // 新增成员,指示结构本身长度 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; // 新增成员,指定窗口的小图标的句柄 } WNDCLASSEX;
1.3.2窗口类的注册与窗口创建、显示和更新 1窗口类的注册 定义一个窗口类结构变量,并初始化便确定了一个指定的窗 口。由于窗口的创建和窗口函数的回调操作都是由操作系统完 成的,因此,在该指定窗口创建之前,必须在系统中注册:通 过调用窗口类函数 RegisterClass 或 RegisterClassEx 用该窗口类 结构变量确定的窗口属性和其关联的主窗口函数。注册函数的 原型和调用实例如下:
⑴窗口类注册函数 RegisterClass 原型: ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); 调用实例: WNDCLASS wndcls; … if(!RegisterClass(&wndcls)) { MessageBox(NULL, TEXT(“This program requires Windows!”), SzAppName, MB_ICONERROR); return 0; }
⑵窗口注册函数扩展版 RegisterClassEx 原型: ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx ); 调用实例: WNDCLASSEX wndcls; … if(!RegisterClassEx(&wndcls)) { MessageBox(NULL, TEXT(“This program requires Windows NT!”), SzAppName, MB_ICONERROR); return 0; }
2窗口的创建 对于已经成功注册的窗口类,便可以调用窗口创建函数 CreateWindow 或 CreateWindowEx 在屏幕上显示所注册窗口类描 述的窗口并成为 Windows 应用程序的运行界面。窗口创建函数 的原型和调用实例如下:
⑴窗口创建函数 CreateWindow 原型: HWND CreateWindow ( LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu HANDLE hInstance, // handle to application instance LPVOID lpParam// pointer to window-creation data );
调用实例: HWND hWnd = CreateWindow ( “MyWndClass”, // 窗口类名 “The Hello Program”, // 窗口名 WS_OVERLAPPEDWINDOW, // 重叠 WS_OVERLAPPEDWINDOW 或 // 子窗口 WS_CHILD、或弹出窗口WS_POPUP。 CW_USERDEFAULT, // 使用窗口缺省水平位置 x = 0。 CW_USERDEFAULT, // 使用窗口缺省垂直位置 y = 0。 CW_USERDEFAULT, // 使用缺省窗宽,系统根据桌面确定。 CW_USERDEFAULT, // 使用缺省窗高,系统根据桌面确定。 NULL, // 无父窗口 NULL, // 使用窗口类结构变量中指定的菜单。 hInstance, // 窗口所属应用程序的句柄。 NULL // 本窗口无须附加参数。 );
⑵窗口创建函数扩展版 CreateWindowEx 原型: HWND CreateWindowEx ( DWORD dwStyle, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu HANDLE hInstance, // handle to application instance LPVOID lpParam// pointer to window-creation data );
调用实例: HWND hWnd = CreateWindowEx ( 0, // 无扩展窗口风格 “MyWndClass”, // 窗口类名 “The Hello Program”, // 窗口名 WS_OVERLAPPEDWINDOW, // 重叠WS_OVERLAPPEDWINDOW 或 // 子窗口WS_CHILD、或弹出窗口WS_POPUP。 CW_USERDEFAULT, // 使用窗口缺省水平位置 x = 0。 CW_USERDEFAULT, // 使用窗口缺省垂直位置 y = 0。 CW_USERDEFAULT, // 使用缺省窗宽,系统根据桌面确定。 CW_USERDEFAULT, // 使用缺省窗高,系统根据桌面确定。 NULL, // 无父窗口 NULL, // 使用窗口类结构变量中指定的菜单。 hInstance, // 窗口所属应用程序的句柄。 NULL // 本窗口无须附加参数。 );
3 窗口的显示与更新 如果调用 CreateWindow或 CreateWindowEx 函数的返回值不为 0时,表明该窗口已成功创建,即系统已为窗口分配了内存, 并返回窗口的句柄。但此时所创建的窗口还未显示,需要调用 函数 ShowWindow显示窗口,并调用函数 UpdateWindow更新窗 口的客户区。这两个函数的原型和调用如下: BOOL ShowWindow( HWND hWnd, // handle to window int nCmdShow// show state of window ); 调用实例:ShowWindow( hWnd, SW_SHOW ); 其中实参 SW_SHOW表示激活由 hWnd索引的窗口,并以当前的 位置和尺寸显示窗口。
系统定义了一系列表示窗口显示状态值,祥见MSDN的有关系统定义了一系列表示窗口显示状态值,祥见MSDN的有关 部分 BOOL UpdateWindow( HWND hWnd/* handle of window */ ); 调用实例:UpdateWindow( hWnd );
1.3.3 启动消息循环 使所创建和显示窗口能够控制程序的运行,接收窗口消息并 做出相应的处理的关键是在 WinMain函数中启动一个消息循环。 正如在前面所述 Windows操作系统把所有驱动程序运行的事 件消息都放入应用程序消息队列,所以应用程序必须不断地从 消息队列中获取消息,并分发给相应的窗口函数,这就是消息 循环所要完成的工作,也是 Windows程序的一个重要特点。最 典型、最简单的消息循环定义如下: