为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

Windows编程基础

2012-06-13 32页 pdf 401KB 88阅读

用户头像

is_436427

暂无简介

举报
Windows编程基础 第 1 章 Windows 编程基础 学习目标 1、Windows 编程基本概念(掌握) 2、Windows GDI 函数的使用(掌握) 3、用消息机制处理用户交互过程(理解) 背景知识 1、C++基础 本章要点 1、Windows GDI 函数 2、Windows 消息机制 引言 Windows 是当今主流的操作系统,也是网络游戏主要的开发平台。不论是网络游戏客户端开发还 是服务器端开发,都有很多成功的网络游戏作品运行于 Window...
Windows编程基础
第 1 章 Windows 编程基础 学习目标 1、Windows 编程基本概念(掌握) 2、Windows GDI 函数的使用(掌握) 3、用消息机制处理用户交互过程(理解) 背景知识 1、C++基础 本章要点 1、Windows GDI 函数 2、Windows 消息机制 引言 Windows 是当今主流的操作系统,也是网络游戏主要的开发平台。不论是网络游戏客户端开发还 是服务器端开发,都有很多成功的网络游戏作品运行于 Windows 操作系统上。虽然对于服务器端开发 来讲,还有 Unix/Linux 以及其他种类的操作系统可以选择,但是相关技术知识相当繁杂,因此本章中 重点介绍 Windows 平台下的程序设计,所涉及到的若干 Windows 编程基础概念对于开发者针对DirectX 程序设计和 WinSock 程序设计的理解和掌握是相当重要的。 Windows 操作系统本身和其上的软件技术发展是相当迅速的,从早期的 Windows 3.1 直到目前的 Windows XP 的各个版本,其功能愈加强大和完善。网络游戏客户端设计所关注的 DirectX 技术也在快 速发展,当开发者对 DirectX 7.0 版本到 DirectX 9.0 版本,甚至即将推出的 DirectX 10.0 版本间的若干 细微变化还应接不暇时,意在整合以 Windows、Xbox、Windows CE 为代的家用电脑、家用游戏机、 移动设备这三种游戏平台的微软新一代“通用软件开发平台”XNA 也已经在如火如荼的之中了, 它的含义是 DirectX&Xbox,NextGeneration,Architecture。 技术的发展如此迅猛,作为游戏开发者来说,意味着需要投入大量的时间和精力去跟踪学习新的 游戏开发技术,这样虽然能够保证游戏的高效开发及技术先进性,但是新技术的学习曲线也是不容忽 视的。开发者应该熟知 Windows 平台的底层开发和高级开发包之间的关系和区别,如果对 Windows 编 程基础还掌握得不是很充分很透彻,那么即使开发包、开发工具再先进,也不能保证开发者可以顺利 进行游戏开发。Windows 基础方式的编程早在 VC 1.5版本的时候就已经很明显了,那就是基于 Windows API 的 SDK 方式的编程,一种 C 风格的 API 编程。随后出现的微软 MFC 库、FCL 库可以理解为是对 Windows API 的重新封装,一种 C++风格的面向对象的编程,从技术学习的角度来看,如果希望掌握 Windows 编程的本质,值得深入研究的是 Windows 底层的 API,也就是 SDK 方式的 Windows 编程, 而且 DirectX 的绝大多数版本及相关技术资料都是采用这种方式来进行开发的,因此虽然本书中的案例 开发采用了 VC.Net 2003 的开发环境,但是本章在介绍 Windows 编程基础的时候,将重点介绍 Windows 的 SDK 方式的开发、消息机制、相关概念及重要的 API 函数。 API 是 Windows SDK 方式开发的基础,Windows 平台上运行的各类软件都可以用 Windows API 来 实现。具体的开发方式非常类似于采用 C 语言的函数库的面向过程的开发,为程序实现一个入口 函数 main,进而实现其他函数,在 main 函数中指定各类函数的调用关系及逻辑。Windows API 同样也 是一个非常庞大的函数库,里面汇聚了 Windows 平台上的各种系统调用函数,可以实现 Windows 窗口 绘制、网络数据包收发、键盘鼠标的输入获取等等众多游戏设计所关注的功能。既然 API 函数如此庞 大,我们的重点又是 Windows SDK 方式的开发,那么对它的学习肯定也不是一蹴而就的。开发者通常 要配备 Windows API 大全、Windows 消息大全这样的参考手册,或者结合微软的 MSDN 来开发,原 因很简单,几乎没有人能对如此大量的 Windows API 函数和这些函数的参数类型、参数个数、函数返 回值、调用方式等熟记于心!本章只拣选对游戏开发比较重要的 Windows API 来介绍,由于开发目的 及实现方式的不同会导致所采用的 API 也各不相同,所以这里的介绍可能不够全面,只能靠开发者不 断地熟悉及实践来扩大知识积累,这一点犹为重要。 当然,在掌握了大量的 Windows API 函数之后,游戏开发者也可以考虑在开发环境上进行变通, 比如不采用 VC.Net 2003 来开发,而采用诸如 Borland C++或者 Delphi 这样的开发环境来开发都是可行 的,关键取决于游戏开发者的技术熟练程度。 1.1 Windows 编程约定 1.1.1 Windows 编程常见缩写 API:Application Programing Interface,应用程序接口。 SDK:Software Development Kit,软件开发包。 MFC:Microsoft Foundation Class,微软基础类库。 MSDN:Microsoft Developer Network,微软开发者网络。 GDI:Graphics Device Interface,图像设备接口。 MDI:Multiple Documents Interface,多重文档界面。 SDI:Simple Document Interface,单文档界面。 1.1.2 Windows 编程常见数据类型 类型定义 含义 BOOL 布尔型(逻辑型)变量(应为 TRUE 或 FALSE) BOOLEAN 布尔型(逻辑型)变量(应为 TRUE 或 FALSE) BYTE 字节(8 位) CCHAR Windows 字符 CHAR Windows 字符 TCHAR 取决于预处理器的符号 UNICODE 是否定义 COLORREF RGB(红绿蓝)颜色值(32 位) CONST 在执行时其值保持不变的变量 DLGPROC 指向应用程序定义的对话框过程回调过程的指针 DWORD 双字(32 位) DWORDLONG 双双字(64 位) FARPROC 指向应用程序定义的指针 FLOAT 浮点型变量 GLOBALHANDLE 全局内存块句柄 HACCEL 加速键表句柄 HANDLE 对象句柄 HBITMAP 位图句柄 HBRUSH 画刷句柄 HDC 设备环境句柄 HFILE 文件句柄 HFONT 字体句柄 HGDIOBJ GDI(图形设备接口)对象句柄 HGLOBAL 全局内存块句柄 HHOOK 钩子句柄 HICON 图标句柄 HINSTANCE 实例句柄 HLOCAL 本地内存句柄 HMENU 菜单句柄 HOOKPROC 指向应用程序定义的钩子的指针 HPALETTE 调色板句柄 HPEN 画笔句柄 HWND 窗口句柄 LOCALHAND 本地内存句柄 LONG 32 位无符号值 LONGLONG 64 位无符号值 LPARAM 32 位消息参数 LPCSTR 指向 Windows 常字符串(以空字符结束)的指针 LPSTR 指向 Windows 字符串(以空字符结束)的指针 LPVOID 指向任意类型的指针 LRESULT 常规函数返回值 MSG Windows 消息 PROC 指向回调函数的指针 SHORT 短整型数 UCHAR 无符号 Windows 字符 UINT 无符号整数 ULONG 无符号长整型数(32 位) USHORT 无符号短整型数(16 位) VOID 任意类型 WINAPI FAR PASCAL 的等价声明方式 WNDPROC 指向在应用程序中定义的窗口过程的指针 WORD 无符号字(16 位) WPARAM 32 位消息参数,早期 Win3.x 中为 16 位 以上列表中包括了字符型、整型、浮点型、布尔型、指针型以及 Windows 应用程序特有的句柄型, 表示指针型的数据类型往往以 P 或 LP 作为前缀,而句柄型总是冠以 H。当然上面的列表并非全部,还 有诸如CALLBACK回调函数的声明方式,WNDCLASS窗口类的声明方式等繁多的类型定义或宏定义。 1.1.3 Windows 编程命名规则 介绍了常见的 Windows 数据类型后,不得不提到著名的“匈牙利命名法”。 1.属性部分: 全局变量: g_ 常量: c_ 类成员变量: m_ 2.类型部分: 指针: p 句柄: h 布尔型: b 浮点型: f 无符号: u 3.描述部分: 初始化: Init 临时变量: Tmp 目的对象: Dst 源对象: Src 窗口: Wnd 了解这种命名规则对理解常见的 Windows 程序非常有帮助,对于代码调试也用途很大,现在可以 结合这种命名规则来理解下面的定义了: hWnd:h 表示句柄,Wnd 表示窗口。 g_bFlag:g 表示全局变量,b 表示布尔型,Flag 表示状态标志。 结合以上介绍的 Windows 编程常见数据类型,对不同类型的句柄进行理解记忆,在后续的 Windows 程序开发中就会受益匪浅。下面我们结合各个项目来具体了解一下这些相关概念。 1.2 Windows 编程基本概念 1.2.1 句柄 几乎 Windows 编程涉及的很多都和句柄有关联。句柄是用来标识项目的,这些项目包括: ● 窗口(window) ● 资源(resource),包括图标(icon),光标(cursor),菜单(menu),字符串(string)等。 ● GDI 对象(GDI object),包括位图(bitmap),画刷(brush),元文件(metafile),调色板(palette),画 笔(pen),区域(region),以及设备环境(device context)。 ● 模块(module) ● 实例(instance) ● 文件(file) ● 内存块(block of memory) ● 控件(control) ● 字体(font) 注:device context 通常译作设备上下文,这里为了理解方便称为“设备环境”。 1. 窗口 “窗口”是 Windows 程序实现的基础,大多数 Windows 程序都是以窗口的方式运行的。网络游戏 客户端编程也要用 DirectX 在窗口基础上实现程序,而网络游戏服务器端编程中,诸如监测工具、GM 工具等程序实现也常以窗口方式运行。在 Windows 开发中,可以通过设置参数来决定窗口类型,这样 可以实现多样的窗口外观,比如有菜单栏的窗口、有状态栏的窗口、有滚动条的窗口等等。从技术角 度上看,每个窗口都具有窗口句柄(HWND 类型的变量),在系统内可以通过窗口句柄定位具体的可 见或不可见的窗口。每个窗口又对应着窗口类,同样的窗口类可以用来创建多个具有相同外观和相同 特性的窗口,例如 Windows 的文件夹可以是相同外观,也可以同时具有相同的特性,可以使用滚动条 浏览文件等等。 2. 资源 “资源”的概念比较广泛,Windows 的视窗系统又实在是庞大而复杂。在 Windows 程序设计中, 对话框、光标、图标、位图、菜单、快捷键、字符串、版本信息等诸多构成窗口的要素都是资源类型。 在 VC 6.0 版本的界面中也提供了专门的 Tab 页来方便开发者对资源进行有效管理并能够将资源进行编 译,存放在.rc 格式的文件中。每个资源都对应唯一的 ID 值,应用程序通过资源 ID 对资源进行定位。 浅显的理解是资源在窗口程序开发中相对固定的窗口要素。实际在窗口程序开发中,不但要通过设计 工具来制作、导入各种资源,还要对这些资源实现代码控制,比如对话框这种资源通常是要对用户的 输入进行响应的,具体能完成什么功能就要靠开发者具体实现。 3. GDI 对象 “GDI 对象”在游戏客户端开发中应用比较少,因为游戏界面的众多元素通常都以图像来实现, 以突出游戏的画面风格。这里需要强调的就是设备环境,通常在 SDK 方式的开发中,都要涉及 HDC 的数据类型,所有的与图形有关的调用将在 HDC 变量初始化后继续进行,所以简单地理解可以认为 HDC 是图像显示设备的一种抽象,这样在进行绘图的时候就可以忽略计算机显卡的具体细节。 4. 模块 “模块”在 Windows 编程中实际上就是对应着 DLL 编程。DLL(Dynamic Link Library,动态链接 库)是在 Windows 系统中广泛采用的函数封装方式。对应于 C 语言中常见的静态函数库.lib 在生成可执 行文件时即参与链接的方式,.dll 可以在可执行文件运行时根据需要将动态链接库加载到内存以继续运 行。这样的动态加载方式的优点显而易见,那就是可以大大地减少可执行文件的大小,对于有大量函 数可以共用的程序非常有优势。比如,Windows 系统是很庞大的,可共用的函数众多。在系统层面上, 早期 windows 版本中采用 user.dll、kernel.dll 和 gui.dll 作为核心的动态链接库,在应用层面上,windows 提供网络连接的库为 ws2_32.dll,也是采用动态链接库实现的。 5. 实例 “实例”也是一种重要的句柄,Windows 系统中创建的各个应用程序都对应着不同的实例句柄。 Windows 是一种多用户操作系统,同样的应用程序可以启动多次。每次开启同样的应用程序时,创建 的实例是不一样。这里需要注意的是实例句柄和窗口句柄的关系:如果应用程序可以开启窗口,那么 一个应用程序可能开启多个窗口,也就是说同样的实例句柄可能关联着多个窗口句柄;如果相同的应 用程序再次启动,同样开启了多个窗口,那么新启动的应用程序具有新的实例句柄以及和这个句柄对 应的新的窗口句柄。 6. 文件 “文件”句柄在 Windows 编程中实现数据永久存储时很重要。在 Windows 平台发展过程中的文件 系统有 FAT、FAT32、NTFS。如果开发者在访问一个文件的时候都要考虑到操作系统存储文件时的数 据组织方式,那么这无疑给开发者带来了很大的负担。因此 Windows API 中封装了与文件操作相关的 大量函数,而这些函数的使用,都和文件句柄有关系。因此文件句柄也是重要的句柄类型。 7. 内存块 “内存块”句柄与 Windows 操作系统在内存管理上的实现方式关系密切。在早期的计算机中通常 可使用的内存和硬盘是严格区分的,并且内存管理上通常都采用特殊的寻址方式,非常不利于开发者 操作内存。而在现代操作系统中,通常都使用了“页”式内存管理,而可寻的地址范围则更大。在 Windows 系统中,应用程序可寻址的内存达到 4G,但实际上低 2G 内存是 Windows 系统使用的,所以通常可以 认为可寻址可使用的内存为 2G。当然,PC 中内存一般没有这么大,此时操作系统会利用硬盘空间“虚 拟”出更多的内存供应用程序使用,但是硬盘数据的存取速度和内存数据的存取速度是无法比拟的, 所以如果程序要大量使用虚拟出来的内存,那么程序本身的响应速度和系统性能都会下降。为了操作 内存就必须使用内存块句柄。 8. 控件 “控件”句柄也是经常使用的一种句柄。现代操作系统往往在软件的可重用性上重点实现。相关 的 OLE 技术、ActiveX 技术代表了 Windows 平台上控件技术的发展。虽然在游戏程序开发当中很少采 用已有的控件,但是对控件技术的掌握可以使得大量的常规程序开发工作变得简单可以利用大量的控 件资源快速地实现程序功能。 9. 字体 “字体”句柄在设计界面信息交互时十分重要。不论是窗口应用开发还是游戏客户端图形图像设 计,从用户使用的角度来讲,图形图像对信息传达的力度是远远不够的,面对计算机,用户获取的大 量信息还是来自于文字信息。对于游戏客户端设计来说,使用字体句柄来指定所要选择的字体库、字 型、字号,可以通过美观的字体来塑造表现力丰富的画面信息,实现玩家与游戏之间、玩家与玩家之 间的信息交流。 句柄的使用通常通过调用特定的 API 函数来进行,例如: //加载资源 ID 为 IDI_WINLOGO 的图标并返回 HICON 类型的句柄 HICON hIcon = LoadIcon(NULL,IDI_WINLOGO); //加载 Windows 默认的箭头鼠标形状并返回 HCURSOR 类型的句柄 LoadCursor(NULL,IDC_ARROW); //取得 Windows 预定义的黑色刷子用来绘制区域并返回 HBRUSH 类型的句柄 HBRUSH hbrBackground = GetStockObject(BLACK_BRUSH); 1.2.2 Windows 消息机制简介 1. 消息 Windows 是一个消息驱动的操作系统,因此理解 Windows 的消息机制非常重要。消息为应用程序 和应用程序间、应用程序和操作系统间提供了信息传递的渠道。在早期的 16 位 Windows 系统中,操 作系统实现为协同式多任务系统,整个系统只有一个消息队列,所有应用程序都要访问这个消息队列 以便检查是否有自己所关心的消息。在后来的 32 位 Windows 系统中,操作系统实现为抢占式多任务 系统,系统中每个运行中的应用程序都有一个消息队列,系统不用等到应用程序完成消息处理就可以 得到控制权。 消息是由消息 ID(UINT)和两个消息参数(WPARAM,LPARAM)构成的。不论是用户和窗口的 键盘鼠标交互还是窗口本身状态的改变,系统都会发送特定的消息到当前窗口,而每个窗口都有预先 指定的消息处理函数(通常是 WndProc),在消息处理函数中会识别系统所发送的消息,根据消息 ID 进行具体处理。 typedef struct tagMSG { //消息结构体 HWND hwnd; //窗口句柄 UINT message; //消息的类型 WPARAM wParam; //消息的额外信息,含义由消息类型确定 LPARAM lParam; //消息的额外信息,含义由消息类型确定 DWORD time; //投递消息的时间 POINT pt; //投递消息时光标的位置 } MSG; 比如,当键盘被按下时,WM_KEYDOWN 消息发送到当前窗口,消息的 WPARAM 参数中包含了 按键的字符信息;当鼠标左键被按下时,WM_LBUTTONDOWN 消息发送到当前窗口,消息的 LPARAM 参数的低 16 位和高 16 位分别封装了鼠标点击时的 x 坐标和 y 坐标;当用户关闭窗口时,WM_QUIT 消息发送到当前窗口,可以识别这个消息做些关闭处理;当用户点击窗口菜单项时,WM_COMMAND 消息发送到当前窗口,可以通过消息参数继续识别所点击的菜单项来进行处理;当窗口需要重新绘制 以显示图形时,WM_PAINT 消息发送到当前窗口,可以在这个消息的处理过程中调用各种绘图 API 来 显示图形,Windows SDK 方式的开发实际上就是开发者根据实现目标选择需要处理的 Windows 消息, 进而对这些消息进行处理,完成应用程序开发。常见的 Windows 消息参见下面的列表 1.1 常见 Windows 消息 消息名称 消息含义 WM_CREATE 应用程序创建一个窗口 WM_DESTROY 一个窗口被销毁 WM_MOVE 移动一个窗口 WM_SIZE 改变一个窗口的大小 WM_ACTIVATE 一个窗口被激活或失去激活状态 WM_SETFOCUS 获得焦点后 WM_KILLFOCUS 失去焦点 WM_ENABLE 改变 Enable 状态 WM_SETREDRAW 设置窗口是否能重画 WM_SETTEXT 应用程序发送此消息来设置一个窗口的文本 WM_GETTEXT 应用程序发送此消息来复制对应窗口的文本到缓冲区 WM_GETTEXTLENGTH 得到与一个窗口有关的文本的长度(不包含空字符) WM_PAINT 要求一个窗口重画自己 WM_CLOSE 当一个窗口或应用程序要关闭时发送一个信号 WM_QUERYENDSESSION 当用户选择结束对话框或程序自己调用 ExitWindows 函数 WM_QUIT 用来结束程序运行或当程序调用 postquitmessage 函数 WM_QUERYOPEN 当用户窗口恢复以前的大小位置时,把此消息发送给某个图标 WM_SHOWWINDOW 当隐藏或显示窗口是发送此消息给这个窗口 WM_DRAWITEM 当控件的可视外观改变时发送此消息给这些控件的拥有者 WM_SETFONT 当绘制文本时程序发送此消息得到控件要用的颜色 WM_GETFONT 应用程序发送此消息得到当前控件绘制文本的字体 WM_SETHOTKEY 应用程序发送此消息让一个窗口与一个热键相关连 WM_GETHOTKEY 应用程序发送此消息来判断热键与某个窗口是否有关联 WM_QUERYDRAGICON 此消息发送给最小化窗口 WM_KEYDOWN 按下一个键 WM_KEYUP 释放一个键 WM_CHAR 按下某键,并已发出 WM_KEYDOWN,WM_KEYUP 消息 WM_SYSKEYDOWN 当用户按住 ALT 键同时按下其它键 WM_SYSKEYUP 当用户释放一个键同时还按着 ALT 键 WM_INITDIALOG 在一个对话框程序被显示前发送此消息 WM_COMMAND 选择一条菜单命令项或当某个控件发送一条消息给它的父窗口 WM_TIMER 发生了定时器事件 WM_MOUSEMOVE 移动鼠标 WM_LBUTTONDOWN 按下鼠标左键 WM_LBUTTONUP 释放鼠标左键 WM_LBUTTONDBLCLK 双击鼠标左键 WM_RBUTTONDOWN 按下鼠标右键 WM_RBUTTONUP 释放鼠标右键 WM_RBUTTONDBLCLK 双击鼠标右键 WM_MBUTTONDOWN 按下鼠标中键 WM_MBUTTONUP 释放鼠标中键 WM_MBUTTONDBLCLK 双击鼠标中键 WM_MOUSEWHEEL 当鼠标滚轮转动时发送此消息 WM_CAPTURECHANGED 当失去捕获的鼠标时发送此消息给窗口 WM_MOVING 移动窗口时发送此消息 WM_CUT 发送此消息给一个编辑框或 ComboBox 来删除当前选择的文本 WM_COPY 发送此消息给一个编辑框或 ComboBox 来复制当前选择的文本 WM_PASTE 发送此消息给 EditControl 或 ComboBox 从剪贴板中得到数据 WM_CLEAR 发送此消息给 EditControl 或 ComboBox 清除当前选择的内容 WM_UNDO 发送此消息给 EditControl 或 ComboBox 撤消最后一次操作 WM_USER 此消息能帮助应用程序自定义消息 Windows 以宏的方式预定义了许多系统消息,开发者也可以自定义消息。 2. 消息循环 Windows 如何处理这些消息呢?这里要重点介绍一下 Windows 系统的消息循环机制。前面提到过, Windows 系统中运行的每个应用程序都拥有自己的消息队列,每个应用程序都通过 while 循环不停地获 取消息,当发现应用程序本身关心的消息时就通过 swtich 语句来分别进行处理,否则就让应用处于空 闲状态。典型的消息循环语句如下: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 关于消息循环中 API 函数的含义将后面结合实际代码来说明,这里先做个了解。 1.3 Windows SDK 典型的程序结构 一个典型的 Win32 窗口应用程序结构从开发逻辑上说是这样的: 程序入口点(WinMain函数) 注册窗口类(RegisterClass 或RegisterClassEx) 创建主窗口(CreateWindow或 CreateWindowEx) 显示主窗口(ShowWindow) 进入消息循环 GetMessage TranslateMessage DispatchMessage 处理各种Windows消息 更新主窗口(UpdateWindow) 程序出口点(WinMain返回) 图 1.1 Win32 窗口应用程序流程图 #include #include //窗口类名和窗口标题 TCHAR szWindowClass[]=_T("演示程序"); TCHAR szWindowTitle[]=_T("主窗口标题"); //窗口过程函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd,msg,wParam,lParam); } } int WINAPI _tWinMain( HINSTANCE hInstance,HINSTANCE,LPTSTR lpCmdLine,int nCmdShow) { //注册窗口类 WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL; RegisterClassEx(&wcex); //创建主窗口 HWND hWnd = CreateWindowEx(0,szWindowClass, szWindowTitle, WS_OVERLAPPEDWINDOW, 128, 96, 512, 480, HWND_DESKTOP, NULL, hInstance, NULL); if (!hWnd) return FALSE; //显示并更新主窗口 ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); // 进入消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; //程序退出 } 首先要包含 windows.h 头文件。为了兼容 UniCode 字体,包含 tchar.h 头文件。再定义两个字符串 szWindowClass 和 szWindowTitle 分别存储窗口类名和窗口标题。 WndProc 函数负责处理窗口消息,在上面的程序段中它只处理了一个消息:WM_DESTROY,其余 的消息通过调用 DefWindowProc 都交给了 Windows 系统去进行缺省处理。对于一个实际的 Windows 应用程序来说,在这个函数中要处理的消息会非常多,然而 ,很多消息要通过调用 DefWindowProc 交给 Windows 系统去进行缺省处理,因为 Windows 消息实在是太多了。注意 WndProc 的参数,HWND 类型的参数 hWnd 是一个窗口句柄,这将告诉 WndProc 处理哪个窗口中的消息,UINT 类型的 msg 是 消息 ID,如果有消息发给窗口 hWnd,则消息有可能带着 WPARAM 和 LPARAM 类型的消息参数以便 提供具体消息信息。 _tWinMain 主函数是整个应用程序的入口。注意主函数的参数,HINSTANCE 类型的变量 hInstance 是应用的实例句柄,Windows 设置这个参数的值并把它传递给应用程序,很多 Windows 函数都要用到 它;第二个 HINSTANCE 类型是该应用的前一应用的实例句柄 hPreInstance,这里并未给出变量名是因 为这个应用并没有父应用,另外这个参数在新版本的 Windows 中已经不再使用,所以不需要关心它; 第三个 LPTSTR 类型的参数 lpCmdLine 是启动此应用时可能跟随的命令行参数,只有从 DOS 命令行输 入或是从 Run 对话框中输入时才起作用,这个也不必关心;第四个整型参数 nCmdShow 是用来控制窗 口显示方式的,比如设置为 SW_SHOWNORMAL 表示默认状态,设置为 SW_MAXIMIZE 或 SW_MINIMIZE 分别表示最大和最小模式等等。 窗口创建之前必须注册窗口类,WNDCLASSEX 类型的变量 wcex 是个很典型的结构体变量,它的 分量中存储着有关窗口类的各个参数,其中:cbSize 是整个 wcex 变量的大小,这里是通过 wcex 变量 的大小来区分 wcex 到底是扩展结构体类型 WNDCLASSEX 还是基本结构体类型 WNDCLASS,这也是 Windows 编程中常见的方式,微软经常把早期开发的数据结构或函数进行增强,而增强后的数据结构 或函数通常都会加上个"EX"后缀;style 是类风格,可以选用 CS_DEFAULT 指定默认风格或者指定 CS_HREDRAW 使一旦客户区宽度发生变化就重新绘制窗口,或指定 CS_VREDRAW 使一旦客户区高 度发生变化就重新绘制窗口,或通过 CS_OWNDC 等参数指定其他风格;lpfnWndProc 是此类窗口的消 息处理函数,在这里指定为 WndProc 函数;cbClsExtra 为额外类空间,可以选择在其中存放窗口类所 共有的数据;cbWndExtra 为额外窗口空间,可以选择在其中存放每个窗口所拥有的数据;hInstance 为 应用程序的实例句柄,标识这个窗口类和哪个应用程序的实例相关联;hIcon 为窗口类的正常图标,当 窗口正常显示或被最大化时,窗口左上角会显示此图标;hCursor 为窗口类的鼠标光标,可以根据需要 将此光标设置成默认的鼠标指针形式或者特殊些的十字光标形式;hbrBackground 为缺省的窗口背景颜 色,lpszMenuName 为缺省的菜单名,用它关联一个默认菜单;lpszClassName 为此窗口类的名称,这 个名字比较重要,因为用这个窗口类实际创建窗口的时候,实际窗口是通过窗口类的名字来指定窗口 类的;hIconSm 为窗口类的小图标,当窗口被最小化时,在 Windows 任务栏中会显示此图标; RegisterClassEx(&wcex) 是将准备好的 wcex 变量注册到 Windows 系统,只有这样才能用这个窗口类创 建实际窗口。实际窗口的创建通过 CreateWindow 函数来完成。在上面的例子中,这个函数为: CreateWindowEx(0,szWindowClass, szWindowTitle, WS_OVERLAPPEDWINDOW, 128, 96, 512, 480, HWND_DESKTOP, NULL, hInstance, NULL); 传递给这个函数的参数不是很清晰,可以参考下面另一段较清晰的代码来理解 CreateWindow 函数 和其各个参数的含义: hWnd=CreateWindow(lpszClassName, //创建窗口,窗口类名 lpszTitle, //窗口实例的标题名 WS_OVERLAPPEDWINDOW, //窗口的风格 CW_USEDEFAULT,CW_USEDEFAULT, //窗口左上角坐标为缺省值 CW_USEDEFAULT,CW_USEDEFAULT, //窗口的高度和宽度为缺省值 NULL, //此窗口没有父窗口 NULL, //此窗口没有主菜单 hInstance, //应用程序当前句柄 NULL); //不使用该值 如果窗口创建成功,那么此函数将返回一个窗口句柄存放在 hWnd 变量中。 if (!hWnd) return FALSE; 这条语句是检查窗口创建是否成功,这也是保证应用程序健壮性的一种很好的编程方式。此时, 即使窗口创建成功,也还不会在屏幕上显示,只是在内存中准备好了显示此窗口所需要的数据。为了 让窗口实际显示,需要调用下面的代码: ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); 这里 ShowWindow 的第一个参数是指定要显示哪个窗口,hWnd 实际上指的是刚刚所创建的那个 窗口;第二个参数是传递过来的决定窗口显示方式的变量。ShowWindow 使窗口显示在屏幕上,而 UpdateWindow 将调整窗口,使之完成一次窗口客户区的重绘。进而要实现该窗口的消息循环,否则此 应用程序会陷入无响应的状态: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; 这是很典型的 Windows 消息循环,其中 GetMessage 函数从窗口的消息队列中取出实际的消息,如 果有消息需要处理,则 GetMessage 返回 TRUE,循环需要继续查看有无后续的消息需要处理。对于取 得的消息,还要通过 TranslateMessage 函数和 DispatchMessage 函数分别对消息进行翻译和分发。 TranslateMessage 主要做一些键盘翻译工作,而 DispatchMessage 负责将消息传递给该窗口的消息处理 函数 WndProc 并调用 WndProc 完成对消息的处理。最后通过 msg.wParam 返回应用的状态。 MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } 在程序代码中遇到上面的消息获取函数也不要诧异,因为这是等同于 GetMessage 的另一种实现方 式,PeekMessage 函数的定义如下,和 GetMessage 函数类似: BOOL PeekMessage( LPMSG lpMsg, // pointer to structure for message HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax, // last message UINT wRemoveMsg // removal flags ); LPMSG lpMsg:是一个 MSG 类型的指针变量。如果有消息在等待,表示消息信息; HWND hWnd:所要检查的消息队列的窗口句柄; UINT wMsgFilterMin,wMsgFilterMax:索引第一个和最后一个消息,一般都会从第一个消息开始 检索,所以通常这两个变量都设置为 0; UINT wRemoveMsg:一般来说,可以是 PM_REMOVE 或 PM_NOREMOVE 的值。使用前者会在 消息被读取后从消息队列中删除,后者是继续保留。通常选择前者 PM_REMOVE。 以上程序代码展示了如何初始化窗口类,如何注册窗口类,如何创建窗口,如何显示窗口,如何 实现消息循环及变通方式实现消息循环,如何在消息处理函数中实现对应用程序所关心的消息的处理。 可以注意到,上面的代码只进行了消息的接收和处理,有些时候,应用程序还要在特定时机主动发送 消息。有两种方式可以发送消息:调用 PostMessage()函数或 SendMessage()函数。函数定义如下: BOOL PostMessage( HWND hWnd, // handle of destination window UINT Msg, // message to post WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); LRESULT SendMessage( HWND hWnd, // handle of destination window UINT Msg, // message to post WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); 这两个函数的参数和前面介绍过的没什么区别,重点介绍一下两个函数的区别。PostMessage()被 经常用来向队列中加入消息,如果调用成功则返回 TRUE,否则返回 FALSE。它只是简单的把消息加 入到队列中,然后返回。多数情况下,调用它将返回 TRUE;SendMessage()则有些不同,它并不是把 消息加入到队列里,而是直接翻译消息和调用消息处理,直到消息处理完成后才返回。所以, SendMessage()比 PostMessage()有更高的实时性。如果应用程序希望立刻做应该做的事情,则应调用 SendMessage()。 1.4 Windows GDI 1.4.1 GDI 资源 1.位图 位图(BITMAP)是用于创建,操作和存储图像的图形对象。位图能够被设备环境(DC)选用。标识位 图的变量类型为位图句柄 HBITMAP。 常见的位图函数有: CreateBitmap: 创建指定宽度,高度和颜色格式的位图 CreateBitmapIndirect: 创建由结构体指定参数的位图 CreateCompatibleBitmap: 创建兼容位图 LoadBitmap: 在可执行文件中加载位图资源 LoadImage: 加载一个 Windows 位图 2. 设备环境 设备环境是一种定义一系列图形对象和相关属性,以及图形模式的结构。标识设备环境的变量类 型是设备环境句柄: HDC。 CreateDC 创建 DC CreateCompatibleDC 创建兼容 DC SelectObject 选用 GDI 对象 DeleteDC 释放 DC 3.画刷 画刷是用于填充矩形、椭圆和通道等封闭图形的 GDI 对象。标识画刷的数据类型为画刷句 柄:HBRUSH。 CreateBrushIndirect 创建由结构体定义的画刷 CreateSolidBrush 创建实体画刷 CreateHatchBrush 创建指定图案类型的画刷 CreatePatternBrush 创建由位图定义的画刷 4.画笔 画笔是用于绘制直线和曲线的图形工具。画笔对应的句柄类型为 HPEN。 CreatePen 创建画笔 CreatePenIndirect 创建由结构体指定参数的画笔 5.字体 字体是用于在显示设备或其他输出设备绘制文本的工具。Win32 API 提供了一系列安装、选用和查 询字体的 API。 CreateFont:创建字体 CreateFontIndirect:创建由结构体定义的字体 6.区域 区域是输出设备显示区域的一部分。区域可以是简单的单个矩形或复杂的多边形和闭合曲线的组 合。区域对应的句柄为 HRGN。 CreateEllipticRgn 创建椭圆区域 CreatePolygonRgn 创建多边形区域 CreateRectRgn 创建矩形区域 CombineRgn 组合区域 1.4.2 窗口绘制 Windows 是一个图形操作系统,可以选择在任意窗口上进行图形绘制。最常见的是在窗口客户 区调用绘图函数进行图形绘制。这里要介绍关于 WM_PAINT 消息和设备环境句柄 HDC 的相关知识。 WM_PAINT 消息在 Windows 中是个很重要的消息。当窗口客户区的部分或全部变得“无效”,以 至于必须刷新,系统将发送这个消息给程序。 1. 发送 WM_PAINT 消息的几种情况 ● 窗口最初创建时; ● 窗口移动后或大小改变后; ● 窗口隐藏后重新显示或被其他窗口遮掩的部分重新可见; ● 调用 InvalidateRect、InvalidateRgn 函数; ● 调用 ScrollWindow 或 ScrollDC 函数滚动客户区; 2. 不发送 WM_PAINT 消息的几种情况 ● 光标穿越客户区; ● 图标拖过客户区; ● 显示对话框; ● 下拉菜单后释放; 3. 常见处理方式 Windows 需要在窗口过程 WndProc 中对于 WM_PAINT 进行处理,常见处理方式总是从 GetDC 调 用开始,而以一个 ReleaseDC 调用结束: hdC=GetDC(hWnd); //画图操作... ReleaseDC(hWnd,hdc); 所有的绘图函数都在这两个函数之间进行调用。GetDC 函数如果调用成功,则会返回一个 hDC 的 设备环境句柄,这个句柄几乎所有的绘图函数都要使用,所以比较重要。另外,Windows 窗口对字符 的显示原理也是绘图,所以 TextOut 这样的显示字符串的函数也是需要使用 hDC 设备环境句柄的。 4. 窗口应用程序输出图形的操作步骤 1)取得指定窗口的当前显示设备环境; 2)选择用户坐标系及映射方式; 3)设定用户坐标系中的观察窗口和设备坐标系中的显示视区; 4)输出图形、文字和图像; 5)释放所使用的显示设备环境; 5. 常见的绘图函数的分类 ● 设备环境函数 ● 椭圆和多边形函数绘图工具函数 ● 位图函数 ● 绘图属性函数 ● 正文函救 ● 映射函数 ● 坐标函数 ● 元文件(metafile)函数 ●
/
本文档为【Windows编程基础】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索