收藏 分享(赏)

Windows编程基础(新手入门).doc

上传人:精品资料 文档编号:8830241 上传时间:2019-07-13 格式:DOC 页数:21 大小:495KB
下载 相关 举报
Windows编程基础(新手入门).doc_第1页
第1页 / 共21页
Windows编程基础(新手入门).doc_第2页
第2页 / 共21页
Windows编程基础(新手入门).doc_第3页
第3页 / 共21页
Windows编程基础(新手入门).doc_第4页
第4页 / 共21页
Windows编程基础(新手入门).doc_第5页
第5页 / 共21页
点击查看更多>>
资源描述

1、第 1章CHAPTERWindows 编程基础基于 Windows 的编程方式有两种。一种是使用 Windows 的 API(Application Programming Interface,应用程序编程接口)函数,通常用 C/C+语言按相应的程序框架进行编程。这些程序框架往往就程序应用提供相应的文档、范例和软件开发工具包(Software Development Kit,SDK) ,所以这种编程方式有时又称为 SDK 方式。另一种是使用“封装”方式,例如 Visual C+的 MFC 方式,它是将 SDK 中的绝大多数函数、数据等按 C+“类”的形式进行封装,并提供相应的应用程序框架和编程

2、操作。事实上,无论是哪种编程方式,人们最关心的内容有三个:一是程序入口,二是窗口、资源等的创建和使用,三是键盘、鼠标等所产生的事件或消息的接收和处理。本章就来讨论这些内容。1.1 从 main 到 WinMain学习编程往往从简单的例子入手,例如一个 C 程序常有下列简单的框架代码:#include int main()printf(“Hello World!n“); /* 输出 */return 0; /* 指定返回值 */事实上,该程序已包括 C 程序中最常用的 #include 指令、必须的程序入口 main 函数、库函数 printf 调用和 return 语句。由于此程序是在早期的

3、DOS(Disk Operating System,磁盘操作系统)环境的字符模型下运行的,因而 printf 函数所输出的都是字符流,也就是说,它在屏幕上输出一行文本“Hello World!”。在 Windows 环境下,这里的屏幕就由控制台窗口来兼作,而基于 Windows 的上述 C 程序代码框架肯定是有所不同的。特别地,由于目前所在的 Windows 环境基本上都是 32 位,所以这里的 Windows 程序平台就是Win32,Windows 编程可直接理解为是 Win32 编程。Visual C+教程(第 2 版)21.1.1 Windows 等价程序等价的 Windows 程序可以

4、写成:HelloMsg.c #include int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int nCmdShow)MessageBox (NULL, TEXT(“Hello, World!“), TEXT(“Hello“), 0) ;return 0 ;在深入剖析上述程序之前,先来看一看在 Visual C+ 6.0 中的编辑、连接和运行的 过程: 选择“开始”“程序”Microsoft Visual Studio 6.0 Microsoft Visual C+ 6.0,运行

5、 Visual C+ 6.0。第一次运行时,将显示如图 1.1 所示的“每日提示”对话框。单击“下一条”按钮,可看到有关各种操作的提示。如果在“启动时显示提示”复选框中单击鼠标,去除复选框的选中标记“ ”,那么下一次运行Visual C+ 6.0,将不再出现此对话框。单击“关闭”按钮关闭此对话框,进入 Visual C+ 6.0 开发环境。 选择“文件”“新建”菜单命令,打开应用程序向导,显示出“新建”对话框,如图 1.2 所示。选择“工程”选项卡,从列表框中选中 Win32 Application(Win32 应用程序)项(图 1.2 中的标记 1) 。 单击“位置”编辑框右侧的“浏览”按钮

6、 (图 1.2 中的标记 2) ,从弹出的 “选择目录”对话框指定项目所在的文件夹,如图 1.3 所示(图中的数字标记表示最经常 的操作次序,下同) 。单击 “确定” 按钮,退出“选择目录”对话框,回到 “新建”对话框中。需要说明的是,为了便于程序的管理和查找,本书所涉及的程序均放入 Visual C+ 6.0的工作文件夹“Visual C+程序”中,第 1 章程序放入子文件夹“第 1 章”中,第 2 章程序放入子文件夹“第 2 章” ,依此类推。 在“新建”对话框的“工程名称”编辑框(图 1.2 中的标记 3)中,输入项目名称 Ex_HelloMsg,保留“平台”下 Win32 复选框的默认

7、“选中 ”状态,单击 “确定”按钮进入下一步。 出现 Win32 Application 向导的“步骤 1 共 1 步”对话框,从中可选择要创建的应用程序类型:“一个空工程” 、 “一个简单的 Win32 程序”和“一个典型的“Hello World! “图 1.1 “每日提示”对话框第 1 章 Windows 编程基础 3程序” ,如图 1.4 所示。它们的区别在于:“一个空工程”仅创建 Win32 应用程序文件框架,不含任何代码;“一个简单的 Win32 程序”是在“一个空工程”基础上添加了程序框架(有入口函数、#include 指令等) ;“一个典型的Hello World!程序”在“一

8、个简单的 Win32 程序”基础上增加了 MessageBox 函数调用,用来输出 “Hello World!”。图 1.2 “新建”对话框“工程”选项卡 图 1.3 “选择目录”对话框 选中“一个空工程” ,单击 “完成” 按钮,弹出“新建工程信息”对话框,如图 1.5所示。单击 “确定” 按钮,系统将按前面的选择自动创建此应用程序。图 1.4 应用程序的向导对话框 图 1.5 “新建工程信息”对话框 再次选择“文件”“新建”菜单命令,Visual C+将打开“新建”对话框并自动切换到“文件”选项卡,如图 1.6 所示。在左侧的文件类型列表中选中 C+ Source File(C+源文件)

9、,在右侧的“文件名”编辑框中输入“HelloMsg.c”或输入“HelloMsg.cpp”(文件扩展名也可不输入,系统会自动添加 cpp 扩展名,cpp 是 C Plus Plus 的缩写,是 C+的 意思) 。 单击 “确定 ”按钮,系统将在创建的 Win32 项目工程 Ex_HelloMsg 中创建并添加Visual C+教程(第 2 版)4一个新的文件 HelloMsg.c,同时打开该文件窗口。现在可以在 HelloMsg.c 中输入前面例HelloMsg.c 中的代码了。输完后,单击编译工具条上的“生成工具”按钮 或直接按 F7键,系统开始对 Ex_HelloMsg 项目工程中的文件进

10、行编译、连接,同时在输出窗口中观察出现的内容,当出现Ex_HelloMsg.exe-0 error(s), 0 warning(s)表示 Ex_HelloMsg.exe 可执行文件已经正确无误地生成了。同时也可看到在文档窗口中所有代码的颜色都发生改变,这是 Visual C+ 6.0 的文本编辑器所具有的语法颜色功能(绿色表示注释,蓝色表示关键字等) 。 单击编译工具条上的 “运行工具”按钮 或直接按 Ctrl+F5 键,就可以运行刚刚生成的 Ex_HelloMsg.exe,结果如图 1.7 所示。单击 “确定 ”按钮,Hello 对话框退出。图 1.6 创建并添加程序文件 图 1.7 开发环

11、境和运行结果1.1.2 头文件HelloMsg.c 是一个#include 预处理指令开始,实际上在用 C/C+编写的 Windows 应用程序的头部都可以看到这样的指令:#include 头文件 Windows.h 是最主要的包含头文件,它还包含了其他一些 Windows 头文件。 例如:windef.h: 基本类型定义winbase.h: 内核函数wingdi.h: 用户接口函数winuser.h: 图形设备接口函数这些头文件定义了 Windows 的所有数据类型、函数调用、数据结构和符号常量,它第 1 章 Windows 编程基础 5们是 Windows 应用程序文档中的一个重要部分。1

12、.1.3 程序入口函数在 C/C+程序中,其入口函数都是 main。但在 Windows 程序中,这个入口函数由WinMain 来代替。该函数是在 winbase.h 中声明的,其原型如下:intWINAPIWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd);可以看出,这个 WinMain 函数除了形参名、个数与 main 函数不同外,类型名也有了新的变化。下面就来分析: WinMain 函数被声明成为返回一个 int 值,同时 WinMain 函数名前还有 WINAPI标识符的修饰

13、。WINAPI 是一种“调用约定”宏,它在 windef.h 中有如下定义:#define WINAPI _ _stdcall所谓“调用约定” ,就是指程序生成机器码后,函数调用的多个参数是按怎样的次 序来传递,同时函数调用结束后堆栈由谁来恢复,以及编译器对函数名的修饰约定等的 协议。函数调用约定“协议”有许多,其中由 WINAPI 宏指定的_ _stdcall 是一个常见的协议,内容包括:参数从右向左压入堆栈;函数自身修改堆栈;机器码中的函数名前面自动加下划线,而函数后面接 符号和参数的字节数。特别地,Visual C+的 MFC 方式却采用了_ _cdecl 调用约定:参数从右向左压入堆栈

14、;传递参数的内存栈由调用者来维护(正因为如此可实现变参函数) ;机器码中的函数名只在前面自动加下划线。 WinMain 函数的第一个和第二个参数都是 HINSTANCE(实例句柄)类型。HINSTANCE 中,H 表示 Handle,是“句柄”的意思。在 Windows 编程中,句柄是一个应用程序用来识别某些资源、状态、模块等的数字。由于句柄唯一标识着对应的资源、状态、模块等,因而使用句柄就是使(调)用相应的资源、状态、模块。当应用程序运行多次时,每一次都是应用程序的“实例” 。由于同一个应用程序的所有实例都共享着应用程序的资源,因而程序通过检查 hPrevInstance 参数就可确定自身的

15、其他实例是否正在运行。 WinMain 函数的第三个参数 lpCmdLine 用来指定程序的命令行,其参数类型为LPSTR。但在 HelloMsg.c 中,却将其改为 PSTR。这两种数据类型都是合法的,也都是指向字符串的指针类型。其中的 STR 是“STRING,字符串”的含义,是指以0 结尾的字符串,LP 前缀表示“长指针 ”,在 Win32 中它与“P ”前缀表示的 “指针”含义相同。 WinMain 函数的第四个参数 nShowCmd 用来指定程序最初显示的方式,它可以是正常、最大化或最小化来显示程序窗口。Visual C+教程(第 2 版)6纵观上述参数和类型名可以发现它们的命名规则

16、: C/C+的类型名仍保留其小写,但新的类型都是用大写字母来命名。 参数名(变量名)都是采用“匈牙利表示法”的命名规则来定义的。它的主要方法是将变量名前后加上表示“类型”和“作用”的“前缀(小写) ”,而变量名本身由“状态” 、 “属性”和“含义”等几个部分组成,每一个部分的名称可以是全称,也可以是缩写,但通常只有第一个字母是大写。例如,hPrevInstance则是由前缀 h(表示“句柄”类型)+状态 Prev(表示“以前的” )+属性Instance(表示“实例” )组成的。1.1.4 MessageBox 函数MessageBox 是一个 Win32 API 函数,用来弹出一个对话框窗口

17、,显示短信息。该函数具有下列原型:int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);其中,第一个参数 hWnd 用来指定父窗口句柄,即对话框所在的窗口句柄。第二、三个参数分别用来指定显示的消息内容(lpText)和对话框窗口的标题(lpCaption) ,最后一个参数用来指定在对话框中显示的预定义的按钮和图标标识,它们是在 winuser.h 定义的一组以 MB_开始的常数组合。例如,下面是在 HelloMsg.c 中改变 MessageBox 的第四个参数。#include int WINAPI

18、 WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int nCmdShow)MessageBox (NULL, TEXT(“Hello, World!“), TEXT(“Hello“),MB_ICONQUESTION | MB_ABORTRETRYIGNORE ) ;return 0 ;程序运行后,结果如图 1.8 所示。可见,MB_ICONQUESTION 用来指定在对话框中显示图标,而 MB_ABORTRETRYIGNORE 用来指定“终止” 、 “重试”和“忽略”按钮,类似这样的预定义标识还有很多

19、,在以后讨论到 MFC 中的 CWnd:MessageBox 函数时还要讨论,故这里不再赘述。在程序 HelloMsg.c 中,调用 MessageBox 的实参中还涉及TEXT 宏。在 Windows 编程中,TEXT 宏是用来对 UNICODE编码的字符串的支持。UNICODE 是使用两个字节表示一个字符,这样单字节的 ANSI 字符和双字节的“汉字”的表示就统一起来了。在程序中使用 TEXT 文本,无论在何 Windows 环境下均图 1.8 第四个参数的作用第 1 章 Windows 编程基础 7可显示正确的内容,而不会出现乱码的情形。另外,还有_TEXT 和_T 宏等,在 Visua

20、l C+中,它们的作用是等同的。1.2 窗口和消息MessageBox 是通过创建的默认“窗口”来显示简单的信息:窗口标题、一行或多行文本、图标和按钮等。在 Windows 环境中,一个“窗口” 就是屏幕上的一个矩形区域,它接收用户的输入,并以文本或图形方式来显示内容。事实上, “窗口”就是用户操作的区域界面,在编程中除创建等操作外,还要处理用户输入、窗口本身事件所产生的“消息” 。1.2.1 程序框架代码为了能处理上述两个部分的内容:窗口创建和消息处理,Windows 提供了相应的程序框架,如下面的例子。HelloWin.c #include LRESULT CALLBACK WndProc

21、 (HWND, UINT, WPARAM, LPARAM); / 窗口过程int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)HWND hwnd ; / 窗口句柄MSG msg ; / 消息WNDCLASS wndclass ; / 窗口类wndclass.style = CS_HREDRAW | CS_VREDRAW ;wndclass.lpfnWndProc = WndProc ;wndclass.cbClsExtra = 0 ;wndclass.cbW

22、ndExtra = 0 ;wndclass.hInstance = hInstance ;wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;wndclass.lpszMenuName = NULL;wndclass.lpszClassName = “HelloWin“; / 窗口类名if (!RegisterClass (return 0

23、 ;/ 创建窗口hwnd = CreateWindow (“HelloWin“, / 窗口类名“我的窗口“, / 窗口标题Visual C+教程(第 2 版)8WS_OVERLAPPEDWINDOW, / 窗口样式CW_USEDEFAULT, / 窗口最初的 x 位置CW_USEDEFAULT, / 窗口最初的 y 位置480, / 窗口最初的 x 大小320, / 窗口最初的 y 大小NULL, / 父窗口句柄NULL, / 窗口菜单句柄hInstance, / 应用程序实例句柄NULL) ; / 创建窗口的参数ShowWindow (hwnd, nCmdShow) ; / 显示窗口Upda

24、teWindow (hwnd) ; / 更新窗口,包括窗口的客户区/ 进入消息循环:当从应用程序消息队列中检取的消息是WM_QUIT时,则退出循环while (GetMessage ( / 转换某些键盘消息DispatchMessage ( / 将消息发送给窗口过程,这里是WndProcreturn msg.wParam ;LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)HDC hdc;PAINTSTRUCT ps;RECT rc;switch (message) case WM_C

25、REATE: / 窗口创建产生的消息return 0 ; case WM_PAINT:hdc = BeginPaint( hwnd, GetClientRect( hwnd, / 获取窗口客户区大小DrawText( hdc, TEXT(“Hello Windows!“), -1, EndPaint( hwnd, return 0 ; case WM_DESTROY: / 当窗口关闭时产生的消息PostQuitMessage (0) ;return 0 ;return DefWindowProc (hwnd, message, wParam, lParam) ; / 执行默认的消息处理创建并运

26、行上述程序时,先创建一个 Ex_HelloWin“空工程” ,然后再创建并添加新的源文件 hellowin.c,输入上述代码,然后编连和运行,结果如图 1.9 所示(里面的框是加上去的,它的区域叫“客户区” ) 。第 1 章 Windows 编程基础 9虽然与 Ex_HelloMsg 示例相比,Ex_HelloWin 要复杂得多,但总可以将其分解成是两个基本函数的程序结构。一个就是前面所讨论的 WinMain 函数,另一个是用户定义的窗口过程函数 WndProc。窗口过程函数 WndProc 用来接收和处理各种不同的消息。 客 户 区 标 题 栏 窗 口 边 框 图 1.9 hellowin.

27、c 运行结果1.2.2 注册窗口类在为程序创建窗口之前,必须首先调用创建 RegisterClass 注册应用程序的窗口类。该函数只要一个参数,即一个指向类型为 WNDCLASS 的结构指针。它包含了一个窗口的基本属性,如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色、处理窗口消息函数的名称等。事实上,注册的过程也就是将这些属性告诉系统,然后再调用CreateWindow 函数创建出窗口。 WNDCLASS 结构具有下列原型:typedef struct UINT style; / 窗口的风格WNDPROC lpfnWndProc; / 指定窗口的消息处理函数的窗口过程函数int cb

28、ClsExtra; / 指定分配给窗口类结构之后的额外字节数int cbWndExtra; / 指定分配给窗口实例之后的额外字节数HINSTANCE hInstance; / 指定窗口过程所对应的实例句柄HICON hIcon; / 指定窗口的图标HCURSOR hCursor; / 指定窗口的鼠标指针HBRUSH hbrBackground; / 指定窗口的背景画刷LPCTSTR lpszMenuName; / 窗口的菜单资源名称LPCTSTR lpszClassName; / 该窗口类的名称 WNDCLASS, *PWNDCLASS;从中可以看出:该结构有 10 个域(成员) ,其中第一个

29、域 style 表示窗口类的风格,它往往是由一些基本的预定义风格通过位的“或”操作(操作符位“|” )组合而成的。例如,在 HelloWin.c 中,有:WNDCLASS wndclass ; / 窗口类wndclass.style = CS_HREDRAW | CS_VREDRAW ;wndclass.lpfnWndProc = WndProc ;Visual C+教程(第 2 版)10wndclass.cbClsExtra = 0 ;wndclass.cbWndExtra = 0 ;wndclass.hInstance = hInstance ;wndclass.hIcon = LoadI

30、con (NULL, IDI_APPLICATION) ;wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;wndclass.lpszMenuName = NULL;wndclass.lpszClassName = “HelloWin“; / 窗口类名可以看到,wndclass.style 被设为 CS_VREDRAW | CS_HREDRAW,表示只要窗口的高度或宽度发生变化,都会重画整个窗口。第二个域 lpfnWndProc 的值为

31、WndProc。表明该窗口类的消息处理函数是 WndProc函数。这里,可简单直接地输入消息处理(窗口过程)函数的函数名即可。接下来的 cbClsExtra 和 cbWndExtra 在大多数情况下都会设为 0。然后的 hInstance 成员,给它的值是由 WinMain 传来的应用程序的实例句柄,表明该窗口与该实例是相关联的。事实上,只要是注册窗口类,该成员的值始终是该程序的实例句柄。下面的 hIcon,是要给这个窗口指定一个图标,LoadIcon (NULL, IDI_APPLICATION) 就是调用系统内部预先定义好的标识符为 IDC_APPLICATION 的图标作为该窗口的图标。

32、同样,LoadCursor (NULL, IDC_ARROW)就是调用预定义的箭型鼠标指针。hbrBackground 域用来定义窗口的背景画刷颜色,也就是该窗口的背景色。调用GetStockObject (WHITE_BRUSH)可以获得系统内部预先定义好的白色画刷作为窗口的背景色。这里 LoadIcon、LoadCursor、GetStockObject 等都是 Windows 的 API 函数,在程序中可直接 调用。lpszMenuName 域的值若为 NULL,则表示该窗口将没有菜单。否则,需要指定表示菜单资源的字符串。 WNDCLASS 结构的最后一个域 lpszClassName

33、是要给这个窗口类起一个唯一的名称,因为 Windows 操作系统中有许许多多的窗口类,必须用一个独一无二的名称来代表它们。通常,可以用程序名来直接作为这个窗口类的名称,它在创建窗口的 CreateWindow 函数中用到。1.2.3 创建和显示窗口当窗口类注册完毕之后,并不会有窗口显示出来,因为注册的过程仅仅是为创建窗口所做的准备工作。实际创建一个窗口是通过调用 CreateWindow 函数完成的。窗口类中已经预先定义了窗口的一般属性,而 CreateWindow 中的参数可以进一步指定一个窗口的更具体的属性,在 HelloWin.c 程序中,是用下列调用 CreateWindow 函数的代

34、码来创建窗 口的: hwnd = CreateWindow (“HelloWin“, / 窗口类名,要与注册时指定的相同“我的窗口“, / 窗口标题WS_OVERLAPPEDWINDOW, / 窗口样式第 1 章 Windows 编程基础 11CW_USEDEFAULT, / 窗口最初的 x 位置CW_USEDEFAULT, / 窗口最初的 y 位置480, / 窗口最初的 x 大小320, / 窗口最初的 y 大小NULL, / 父窗口句柄NULL, / 窗口菜单句柄hInstance, / 应用程序实例句柄NULL) ; / 创建窗口的参数CreateWindow 函数的第一个参数是创建该

35、窗口所使用的窗口类的名称,注意这个名称应与前面所注册的窗口类的名称一致。第三个参数为创建的窗口的风格,它们通常是一些预定义风格的“|”组合。其中, WS_OVERLAPPEDWINDOW 表示创建一个层叠式窗口,有边框、标题栏、系统菜单、最大化和最小化按钮等。CreateWindow 函数后面的参数中,仍用到了该应用程序的实例句柄 hInstance。如果窗口创建成功,返回值是新窗口的句柄,否则返回 NULL。窗口创建后,并不会在屏幕上显示出来。要能真正把窗口显示在屏幕上,还得使用 ShowWindow 函数,其原型如下:BOOL ShowWindow( HWND hWnd, int nCmd

36、Show ); 其中,参数 hWnd 指定要显示得窗口的句柄,nCmdShow 表示窗口的显示方式,这里指定为从 WinMain 函数的 nCmdShow 所传递而来的值。由于 ShowWindow 函数的执行优先级不高,所以当系统正忙着执行其他的任务时,窗口不会立即显示出来,此时,调用 UpdateWindow 函数以可以立即显示窗口。同时,它将会给窗口过程发出 WM_PAINT 消息。1.2.4 消息和消息处理1消息循环在 Win32 编程中,消息循环是相当重要的一个概念,看似很难,但使用起来却是非常简单。在 WinMain 函数的最后,有下列代码:while (GetMessage (

37、/ 转换某些键盘消息DispatchMessage ( / 将消息发送给窗口过程,这里是WndProcWindows 应用程序可以接收以各种形式输入的信息,这包括键盘、鼠标动作、计时器产生的消息,也可以是其他应用程序发来的消息等。Windows 系统自动监控所有的输入设备,并将其消息放入该应用程序的消息队列中。GetMessage 函数就是用来从应用程序的消息队列中按照先进先出的原则将这些消息一个个地取出来,放进一个 MSG 结构中去。它的原型如下:Visual C+教程(第 2 版)12BOOL GetMessage( LPMSG lpMsg, / 指向一个MSG结构的指针,用来保存消息HW

38、ND hWnd, / 指定哪个窗口的消息将被获取UINT wMsgFilterMin, / 指定获取的主消息值的最小值UINT wMsgFilterMax / 指定获取的主消息值的最大值);GetMessage 函数用来将获取的消息复制到一个 MSG 结构中。如果队列中没有任何消息,该函数将一直空闲直到队列中又有消息时再返回。如果队列中已有消息,它将取出一个后返回。MSG 结构包含 Windows 消息的完整信息,其定义如下:typedef struct HWND hwnd; / 消息发向的窗口的句柄UINT message; / 主消息的标识值WPARAM wParam; / 附消息值,其具

39、体含义依赖于主消息值LPARAM lParam; / 附消息值,其具体含义依赖于主消息值DWORD time; / 消息放入消息队列中的时间POINT pt; / 消息放入消息队列时的鼠标坐标 MSG, *PMSG;上述结构中的主消息表明了消息的类型,例如,是键盘消息还是鼠标消息等,附消息的含义则依赖于主消息值,例如,如果主消息是键盘消息,那么附消息中则存储了是键盘的哪个具体键的信息。事实上,GetMessage 函数还可以过滤消息,它的第二个参数是用来指定从哪个窗口的消息队列中获取消息,其他窗口的消息将被过滤掉。如果该参数为 NULL,则GetMessage 从该应用程序线程的所有窗口的消息

40、队列中获取消息。第三个和第四个参数是用来过滤 MSG 结构中主消息值的,主消息值在 wMsgFilterMin 和 wMsgFilterMax 之外的消息将被过滤掉。如果这两个参数为 0,则表示接收所有消息。特别地,当且仅当 GetMessage 函数在获取到 WM_QUIT 消息后,将返回 0 值,于是程序退出消息循环。TranslateMessage 函数的作用是把虚拟键消息转换到字符消息,以满足键盘输入的需要。DispatchMessage 函数所完成的工作是把当前的消息发送到对应的窗口过程中去。2消息处理用于消息处理的函数又叫窗口过程,在这个函数中,不同的消息将用 switch 语句分

41、配到不同的处理程序中去。Windows 的消息处理函数都有一个确定的统一方式,即这种函数的参数个数和类型以及其返回值的类型都有明确的规定。在 HelloWin.c 中,WinProc 函数明确处理了 3 个消息,分别是 WM_CREATE(创建窗口消息) 、WM_PAINT(窗口重画消息) 、WM_DESTROY(销毁窗口消息) 。事实上,应用程序发送到窗口的消息远远不止以上这几条,像WM_SIZE、WM_MINIMIZE、WM_MOVE 等这样经常使用的消息就有好几十条。为了减轻编程的负担,Windows 的 API 提供了 DefWindowProc 函数来处理这些最常用的消息,调用这个函

42、数后,这些消息将按照系统默认的方式得到处理。第 1 章 Windows 编程基础 13因此,在 switch 语句中,只需明确处理那些有必要进行特别响应的消息,把其余的消息交给 DefWindowProc 函数来处理,即将消息的控制交由 Windows 进行默认处理,这是一种明智的选择。 3结束消息循环 当用户按 Alt+F4 键或单击窗口右上角的 “退出”按钮,系统就向应用程序发送一条WM_DESTROY 的消息。在处理此消息时,调用了 PostQuitMessage 函数,该函数会向窗口的消息队列中发送一条 WM_QUIT 消息。在消息循环中,GetMessage 函数一旦检索到这条消息,

43、就会返回 FALSE,从而结束消息循环,随后程序也结束。1.2.5 WM_PAINT 消息WM_PAINT 是 Win32 的图形和文本编程中经常使用到的消息。当窗口客户区的一部分或全部变成“无效”时,则必须 “刷新”重绘,此时将向程序发出此消息。那么客户区怎么会“无效”呢?在最初窗口创建时,整个客户区都是“无效”的,因为窗口上还没有绘制任何东西。所以,在创建窗口时,会发出第一个 WM_PAINT 消息。在 HelloWin.c 程序中,由于在注册窗口时,指定了 wndclass.style 的风格为CS_VREDRAW 和 CS_HREDRAW,这表明只要窗口的高度或宽度发生变化,就将使整个

44、窗口“无效” ,从而发出 WM_PAINT 消息,使得系统重画整个窗口。当窗口最小化再恢复为以前的大小时,Windows 将令窗口“无效” ,并发出WM_PAINT 消息使系统重画整个窗口。当窗口移至与另一窗口有重叠被遮挡时,Windows 也将窗口视为“无效 ”,发出 WM_PAINT 消息以便刷新窗口。在窗口过程函数 WndProc 中,WM_PAINT 消息处理通常总是从 BeginPaint 函数开始,而从 EndPaint 函数结束。BeginPaint 函数用来返回指定窗口句柄的设备描述表句柄,设备描述表用来将程序与计算机外部输出设备连接起来。hdc 定义的是句柄 HDC 变量,

45、DrawText 等 GDI 函数都需要通过这样的 HDC 句柄来绘制图形和文本。EndPaint 用来释放设备描述表句柄,并使先前无效区域变为有效,从而使 Windows 不再发送 WM_PAINT 消息。PAINTSTRUCT 是“绘图信息结构” ,BeginPaint 和 EndPaint 函数都需要 PAINTSTRUCT 结构变量作为自己的参数。需要说明的是,BeginPaint 和 EndPaint 函数必须成对出现,所有 GDI 函数的调用也应在这两个函数之间进行。DrawText 函数用来在参考矩形内使用指定的格式来绘制文本,它的函数原型如下:int DrawText(HDC

46、hDC, / 绘制设备的句柄LPCTSTR lpString, / 要绘制的文本int nCount, / 文本的字符个数LPRECT lpRect, / 参考矩形UINT uFormat / 文本绘制格式);Visual C+教程(第 2 版)14其中,当 nCount 为1 时,表示 lpString 指定的是以“0 ”为结尾的字符串,并自动计算该字符串的字符个数。lpRect 是一个指向 RECT 类型的“ 矩形”结构指针,该“矩形”结构含有 left、top、right 和 bottom 4 个 LONG 域。为了能在窗口客户区中间绘制文本,该函数的 lpRect 被填为 RECT 变

47、量 rc 的指针,它通过调用 GetClientRect 函数,获取hwnd 窗口的客户区大小。同时,指定 uFormat 格式为 DT_SINGLELINE(单行输出) 、DT_CENTER(水平居中)和 DT_VCENTER(垂直居中) 。1.2.6 Windows 基本数据类型在前面示例和函数原型中,有一些“奇怪”的数据类型,如前面的 HINSTANCE 和LPSTR 等,事实上,很多这样的数据类型只是一些基本数据类型的别名,以方便不同风格的程序员使用。表 1.1 列出了一些在 Windows 编程中常用的基本数据类型;表 1.2 列出了常用的预定义句柄,它们的类型均为 void *,即

48、一个 32 位指针。表 1.1 Windows 编程中常用的基本数据类型Windows 所用的数据类型 对应的基本数据类型 说明BOOL bool 布尔值BSTR unsigned short * 32 位字符指针BYTE unsigned char 8 位无符号整数COLORREF unsigned long 用作颜色值的 32 位值DWORD unsigned long 32 位无符号整数,段地址和相关的偏移地址LONG long 32 位带符号整数LPARAM long 作为参数传递给窗口过程或回调函数的 32 位值LPCSTR const char * 指向字符串常量的 32 位指针LPSTR char * 指向字符串的 32 位指针LPVOID void * 指向未定义类型的 32 位指针LRESULT long 来自窗口过程或回调函数的 32 位返回值UINT unsigned int 32 位无符号整数WORD unsigned short 16 位无符号整数WPARAM unsigned int 当做参数传递给窗口过程或回调函数的 32 位值说明: 这些基本数据类型都是用大写字符来表示的,以与一般 C/C+基本数据类型相 区别。 若数据类型的前缀是 P 或 LP,则表示该类型是一个指针或长指针数

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报