Visual c 第2章 Windows编程与MFc基础 要想熟练掌握 Windows应用程序的开发,首先需要理解 Windows平台下程序运行的内部机制。本 章首先将剖析 Windows程序的内部运行机制,为读者扫清VC++学习路途中的第一个障碍,而后简单 介绍一下MFC的基础知识,为进一步学习MFC程序开发打下基础 2.1 Windows编程基础 Windows操作系统采用了图形用户界面,借助于它提供的API( Application P Interface)函数,用户可以编出具有漂亮图形界面的程序。本节将主要介绍一下涉及 Windows编程中 用到的一些概念 2.1.1 Windows ap|函数 为方便用户开发 Windows应用程序, Windows操作系统提供了各种各样的函数。这些函数是 Windows操作系统提供给应用程序编程的接口( Application Programming Interface),简称为API函数 用户在编写 Windows程序时所说的API函数,就是指系统提供的函数,所有主要的 Windows函数都在 “ Windows.h”头文件中进行了声明 Windows apl也是 Windows操作系统自带的在 Windows环境下运行的软件开发包(SDK)。程序员 总是直接或间接引用AP进行应用程序的开发,所以 Windows应用程序就有大致相同的用户界面 SDK的全称是 Software Development Kit,中文译为软件开发包。假如现在需要开发视频会议系 说明统,在购买视频数据采集卡时,厂商就会提供频数据采集卡的SDK开发包,以方便对频数据采 集卡的编程操作。这个开发包通常都会包含频数据采集卡的API函数库、帮助文档、使用手册 和辅助工具等资源。也就是说,SDK实际上就是开发所需资源的一个集合。 2.1.2窗口与句柄 窗口是 Windows应用程序中一个非常重要的元素,它是 Windows应用程序与用户进行交互的接口。 Windows应用程序至少要有一个窗口,称为主窗口。通过窗口,可以接收用户的输入,并显示输出。 个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小(大)化按钮、边框和滚动条等 窗口可以分为客户区和非客户区。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘 制图形。标题栏、菜单栏、系统菜单、最小(大)化按钮和边框统称为窗口的非客户区,它们由 Windows系统来管理,而应用程序则主要管理客户区的外观及操作 在 Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。要对某个窗口进行操作,首 先就要得到这个窗口的句柄。句柄( HANDLE)是 Windows程序中一个重要的概念。在 Windows程序 中,有各种各样的资源(窗口、图标和光标等),系统在创建这些资源时会为它们分配内存,并返回 励志照亮人生编程改变命运
30 励志照亮人生 编程改变命运 零基础学 Visual C++ 第2 章 Windows编程与MFC基础 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制。本 章首先将剖析Windows程序的内部运行机制,为读者扫清VC++学习路途中的第一个障碍,而后简单 介绍一下MFC的基础知识,为进一步学习MFC程序开发打下基础。 2.1 Windows编程基础 Windows操作系统采用了图形用户界面,借助于它提供的API(Application Programming Interface)函数,用户可以编出具有漂亮图形界面的程序。本节将主要介绍一下涉及Windows编程中 用到的一些概念。 2.1.1 Windows API函数 为方便用户开发Windows应用程序,Windows操作系统提供了各种各样的函数。这些函数是 Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称为API函数。 用户在编写Windows程序时所说的API函数,就是指系统提供的函数,所有主要的Windows函数都在 “Windows.h”头文件中进行了声明。 Windows API也是Windows操作系统自带的在Windows环境下运行的软件开发包(SDK)。程序员 总是直接或间接引用API进行应用程序的开发,所以Windows应用程序就有大致相同的用户界面。 说明 SDK的全称是Software Development Kit,中文译为软件开发包。假如现在需要开发视频会议系 统,在购买视频数据采集卡时,厂商就会提供频数据采集卡的SDK开发包,以方便对频数据采 集卡的编程操作。这个开发包通常都会包含频数据采集卡的API函数库、帮助文档、使用手册 和辅助工具等资源。也就是说,SDK实际上就是开发所需资源的一个集合。 2.1.2 窗口与句柄 窗口是Windows应用程序中一个非常重要的元素,它是Windows应用程序与用户进行交互的接口。 一个Windows应用程序至少要有一个窗口,称为主窗口。通过窗口,可以接收用户的输入,并显示输出。 一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小(大)化按钮、边框和滚动条等。 窗口可以分为客户区和非客户区。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘 制图形。标题栏、菜单栏、系统菜单、最小(大)化按钮和边框统称为窗口的非客户区,它们由 Windows系统来管理,而应用程序则主要管理客户区的外观及操作。 在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。要对某个窗口进行操作,首 先就要得到这个窗口的句柄。句柄(HANDLE)是Windows程序中一个重要的概念。在Windows程序 中,有各种各样的资源(窗口、图标和光标等),系统在创建这些资源时会为它们分配内存,并返回
第3章 Windows编程与MFC 标识这些资源的标识号,即句柄 Windows中,常用句柄类型及其说明如表2.1所示。 表21常用句柄类型及其说明 HWND 窗口句柄 HDC 设备环境句柄 HBITMAP 位图句柄 HCURSOR 光标句柄 HICON 图标句柄 HFONT 字体句柄 HMENU 菜单句柄 HEN 画笔句柄 文件句柄 HBRUSH 画刷句柄 HINSTANCE 当前实例句柄 HLOCAL 局部内存对象句柄 HGLOBAL 全局内存对象句柄 2.1.3事件与消息 Windows程序采用的是事件驱动方式的程序设计模式,其操作主要是基于消息的。在应用程序启 动后,系统等待用户在图形用户界面内的输入选择, 如鼠标按键、键盘按键、窗口被创建、关闭、改变事 大小和移动等,对系统而言,这些都是事件。 键盘消息 Windows[鼠标消息息 提取消息 只要有事件发生,系统即产生特定的消息。消息 系统其他消息队 描述了事件的类别,包含了相关信息, Windows应用 处理消息 程序利用消息与系统及其他应用程序进行信息交换。 由于 Windows事件的发生是随机的,程序的执 图2.1事件与消息处理 行先后顺序也无法预测,系统采用消息队列来存放 事件发生的消息,然后从消息队列中依次取出消息进行相应的处理,可表示为如图2.1所示 2.14常用的 Windows数据类型 Windows应用程序中常用的数据类型如表22所示 表22 Windows应用程序常用的数据类型 数据类型 BYTE 8位无符号字符 PSTR 32位字符指针 COLORREF 32位整数,表示一个颜色 WORD 16位无符号整数 LONG 32位有符号整数 DWORD 32位无符号整数,是WORD的两倍长度 UINT 32位无符号整数 BOOL 布尔值,值为TRUE或 FALSE HANDLE 励志照亮人生编程改变命
31 励志照亮人生 编程改变命运 第 3 章 Windows编程与MFC基础 标识这些资源的标识号,即句柄。 Windows中,常用句柄类型及其说明如表2.1所示。 表2.1 常用句柄类型及其说明 句柄 说明 句柄 说明 HWND 窗口句柄 HDC 设备环境句柄 HBITMAP 位图句柄 HCURSOR 光标句柄 HICON 图标句柄 HFONT 字体句柄 HMENU 菜单句柄 HPEN 画笔句柄 HFILE 文件句柄 HBRUSH 画刷句柄 HINSTANCE 当前实例句柄 HLOCAL 局部内存对象句柄 HGLOBAL 全局内存对象句柄 2.1.3 事件与消息 Windows程序采用的是事件驱动方式的程序设计模式,其操作主要是基于消息的。在应用程序启 动后,系统等待用户在图形用户界面内的输入选择, 如鼠标按键、键盘按键、窗口被创建、关闭、改变 大小和移动等,对系统而言,这些都是事件。 只要有事件发生,系统即产生特定的消息。消息 描述了事件的类别,包含了相关信息,Windows应用 程序利用消息与系统及其他应用程序进行信息交换。 由于Windows事件的发生是随机的,程序的执 行先后顺序也无法预测,系统采用消息队列来存放 事件发生的消息,然后从消息队列中依次取出消息进行相应的处理,可表示为如图2.1所示。 2.1.4 常用的Windows数据类型 Windows应用程序中常用的数据类型如表2.2所示。 表2.2 Windows应用程序常用的数据类型 数据类型 说 明 BYTE 8位无符号字符 PSTR 32位字符指针 COLORREF 32位整数,表示一个颜色 WORD 16位无符号整数 LONG 32位有符号整数 DWORD 32位无符号整数,是WORD的两倍长度 UINT 32位无符号整数 BOOL 布尔值,值为TRUE或FALSE HANDLE 句柄 图2.1 事件与消息处理 事件 键盘消息 应用程序 提取消息 处理消息 鼠标消息 其他消息 消 息 队 列 Windows 系统
Visual c++ (续) 数据类型 LPSTR 32位指针,指向 LPCSTR 32位指针,指向字符串常量 LPTSTR 32位指针,指向字符串,此字符串可移植到 Unicode和DBCS双字符集 LPCTSTR 32位指针,指向字符串常量,此串可移植到 Unicode和DBCS双字符集 LPVOID 32位指针,可指向任何类型数据 LPRESULT 32位数值,作为窗口函数或 CALLBACK函数的返回类型 WNDPROC 32位指针,指向一个窗口函数 LPARAM 32位数值,作为窗口函数和 CALLBACK函数的参数 WPARAM 作为窗口函数和 CALLBACK函数的参数,在win16中是16位,在win32中是32位 2.2 Windows应用程序分析 Winmain和 WinProc函数构成了 Windows应用程序的主体。 Winmain函数负责建立窗口和建立消 息循环, WndProc函数负责消息的处理。典型的 Windows窗口的创建与处理过程可表示为图2.2所示。 程序开始执行 WndProc 程序打开窗口 函数负责 函数负责 应用程序 处理消息 处理消息」 程序结束 关闭窗口 默认处理 图22 Windows窗口创建及处理过程 2.2.1 Winmain函数 传统的DOS程序以main函数作为进入程序的初始入口点,在 Windows应用程序中,main函数被 Winmain函数取代。当 Windows操作系统启动一个程序时,它调用的就是该程序的 Winmain函数。 WinMain函数是 Windows程序的入口点函数,当 WinMain函数结束或返回时, Windows应用程序结束 WinMain函数的原型如下 int WINAPI WinMain C HINSTANCE hThisInst //应用程序当前实例句柄 INSTANCe hPrevInst //应用程序其他实例句柄 LPSTR lpszCmdLine //指向程序命令行参数的指针 Int nCmdshow, //应用程序开始执行时窗口显示方式的整数值标识 励志照亮人生编程改变命运
32 励志照亮人生 编程改变命运 零基础学 Visual C++ (续) 数据类型 说 明 LPSTR 32位指针,指向字符 LPCSTR 32位指针,指向字符串常量 LPTSTR 32位指针,指向字符串,此字符串可移植到Unicode和DBCS双字符集 LPCTSTR 32位指针,指向字符串常量,此串可移植到Unicode和DBCS双字符集 LPVOID 32位指针,可指向任何类型数据 LPRESULT 32位数值,作为窗口函数或CALLBACK函数的返回类型 WNDPROC 32位指针,指向一个窗口函数 LPARAM 32位数值,作为窗口函数和CALLBACK函数的参数 WPARAM 作为窗口函数和CALLBACK函数的参数,在win 16中是16位,在win 32中是32位 2.2 Windows应用程序分析 WinMain和WinProc函数构成了Windows应用程序的主体。WinMain函数负责建立窗口和建立消 息循环,WndProc函数负责消息的处理。典型的Windows窗口的创建与处理过程可表示为图2.2所示。 图2.2 Windows窗口创建及处理过程 2.2.1 WinMain函数 传统的DOS程序以main函数作为进入程序的初始入口点,在Windows应用程序中,main函数被 WinMain函数取代。当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数。 WinMain函数是Windows程序的入口点函数,当WinMain函数结束或返回时,Windows应用程序结束。 WinMain函数的原型如下: int WINAPI WinMain ( HINSTANCE hThisInst, //应用程序当前实例句柄 HINSTANCe hPrevInst, //应用程序其他实例句柄 LPSTR lpszCmdLine, //指向程序命令行参数的指针 Int nCmdShow, //应用程序开始执行时窗口显示方式的整数值标识 ) 程序开始执行 程序打开窗口 否 是 否 应用程序 处理消息 是 处理消息 程序结束, 关闭窗口 检测发向窗口 的消息 WM_QUIT WinMain() 函数负责 windows 默认处理 WndProc() 函数负责
第3章 Windows编程与MFC 口参数 hInstance表示该程序当前运行的实例的句柄,这是一个数值。当程序在 Windows下运行时, 它唯一标识运行中的实例。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该 实例分配一个句柄值,并通过 hInstance参数传递给 Winmain函数 口参数 hPrevInstance表示当前实例的前一个实例的句柄。在Win32环境下,这个参数不再起作用, 为NULL 口参数 IpCmdLine是一个字符串指针,指定传递给应用程序的命令行参数。 口参数 n DshOw指定程序的窗口应该如何显示,例如最大化、最小化、隐藏等。这个参数的值 由该程序的调用者所指定,应用程序通常不需要去理会这个参数的值。 WinMain函数接收4个参数,这些参数都是在系统调用 WinMain函数时,传递给应用程序的 222创建窗口 创建一个完整的窗口,需要经过下面4个操作步骤:定义窗口类、注册窗口类、创建窗口实例 显示及更新窗口。 定义窗口类 在创建一个窗口前,必须对该类型的窗口进行设计,指定窗口的特征。窗口的特征是由 WNDCLASS结构体来定义的。 WNDCLASS结构体的定义如下: typedef struct tagWNDCLASS UINT style; //窗口风格 WNDPRoC lpfnwndProc //指向窗口处理函数的函数指针 nt cbclsextra //窗口结构中的预留字节数 int cbwndextra: //为其他创建窗口预留字节数 ANCe hInstance //注册该窗口类的实例句柄 HICON Icon //代表该窗口类 标 HCURSOR hours //该窗口客户区鼠标光标句柄 HBRUSH hbrBackGround //该窗口背景颜色句柄 LPCSTR Ips zMenuName //指向窗口菜单名的字符指针 //指向窗口名的字符指针 1 WNDCLASS, *PWNDCLASS, NEAR *NPWNDCLASS, FAR *LPWNDCLASS 2.注册窗口类 窗口类( WNDCLASS)设计完成后,需要调用 RegisterClasso函数对其进行注册,注册成功后, 才可以创建该类型的窗口。注册函数的原型声明如下: BOOL Registerclass(CoNST WNDCLAss *lpwndclass) 该函数只有一个参数,即上一步骤中所设计的窗口类对象的指针。 3.创建窗口实例 设计好窗口类并且将其成功注册之后,就可以用 Create Window(函数产生这种类型的窗 数 Create Window(原型如下 HWND Createwindow (LPCTSTR IpszClassName //窗口类名 励志照亮人生编程改变命
❑ 参数hInstance表示该程序当前运行的实例的句柄,这是一个数值。当程序在Windows下运行时, 它唯一标识运行中的实例。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该 实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。 ❑ 参数hPrevInstance表示当前实例的前一个实例的句柄。在Win32环境下,这个参数不再起作用, 为NULL。 ❑ 参数lpCmdLine是一个字符串指针,指定传递给应用程序的命令行参数。 ❑ 参数nCmdShow指定程序的窗口应该如何显示,例如最大化、最小化、隐藏等。这个参数的值 由该程序的调用者所指定,应用程序通常不需要去理会这个参数的值。 WinMain函数接收4个参数,这些参数都是在系统调用WinMain函数时,传递给应用程序的。 2.2.2 创建窗口 创建一个完整的窗口,需要经过下面4个操作步骤:定义窗口类、注册窗口类、创建窗口实例、 显示及更新窗口。 1. 定义窗口类 在创建一个窗口前,必须对该类型的窗口进行设计,指定窗口的特征。窗口的特征是由 WNDCLASS结构体来定义的。WNDCLASS结构体的定义如下: typedef struct tagWNDCLASS { UINT style; //窗口风格 WNDPROC lpfnWndProc; //指向窗口处理函数的函数指针 int cbClsExtra; //窗口结构中的预留字节数 int cbWndExtra; //为其他创建窗口预留字节数 HINSTANCE hInstance; //注册该窗口类的实例句柄 HICON hIcon; //代表该窗口类的图标句柄 HCURSOR hCursor; //该窗口客户区鼠标光标句柄 HBRUSH hbrBackGround; //该窗口背景颜色句柄 LPCSTR lpszMenuName; //指向窗口菜单名的字符指针 LPCSTR lpszClassName; //指向窗口名的字符指针 } WNDCLASS, *PWNDCLASS,NEAR *NPWNDCLASS, FAR *LPWNDCLASS; 2. 注册窗口类 窗口类(WNDCLASS)设计完成后,需要调用RegisterClass()函数对其进行注册,注册成功后, 才可以创建该类型的窗口。注册函数的原型声明如下: BOOL RegisterClass(CONST WNDCLASS *lpWndClass); 该函数只有一个参数,即上一步骤中所设计的窗口类对象的指针。 3. 创建窗口实例 设计好窗口类并且将其成功注册之后,就可以用CreateWindow()函数产生这种类型的窗口了。函 数Create Window()原型如下: HWND CreateWindow (LPCTSTR lpszClassName, //窗口类名 33 励志照亮人生 编程改变命运 第 3 章 Windows编程与MFC基础
Visual c++ //窗口标题名 DWORD dwstyle //创建窗口的样式 int x,y, //窗口左上角坐标 int nwidth, nHeight, //窗口宽度和度高 HWND hwndparent //该窗口的父窗口句柄 HWENU hMenu, //窗口主菜单句柄 STANCe hInstance //创建窗口的应用程序当前句柄 LPVOID IpParam //指向一个传递给窗口的参数值的指针 注意区分 WNDCLASS中的 Istyle成员与 Create Window函数的 dwStyle参数,前者是指定窗口类的 样式,基于该窗口类创建的窗口都具有这些样式,后者是指定某个具体的窗口的样式。 4.显示及更新窗口 窗口创建之后,就可以调用函数 Show Window(来显示窗口,该函数的原型如下 BOOL Showwindow( HWND hwnd, int ncmdshow Show Window函数有两个参数,第一个参数hWnd就是在上一步骤中成功创建窗口后返回的那个 窗口句柄:第二个参数 nCmdShow指定了窗口显示的状态。 在调用 Show Window函数之后,紧接着调用 Update Window函数来刷新窗口。 Update Window( 函数的原型如下: 其参数hwnd指的是创建成功后的窗口的句柄。 Update Window(函数通过发送一个 WM PAINT消 息来刷新窗口, Update Window函数将 WM PAINT消息直接发送给窗口过程函数进行处理,而没有 放到消息队列里。到此,一个窗口就算创建完成了 2.2.3消息循环 在创建窗口、显示窗口和更新窗口后,就需要编写一个消息循环,不断地从消息队列中取出消息, 并进行响应。要从消息队列中取出消息,需要调用 GetMessage(函数,其原型如下: GetMessage //指向MsG结构的指针 //窗口句柄 nMsgFilteMin, //用于消息过滤的最小消息号值 nMsgEilterMax /用于消息过滤的最大消息号值 只要从消息队列中取出消息不为WM_QUIT, GetMessageo函数就返回一个非零值,否则程序就 结束循环并退出。 通常编写的消息循环代码如下: while (GetMessage (&Msg, NULL, 0,0)) TranslateMessage(&Msg) //将消息的虚拟键转换为字符信息 DispatchMessage(&Msg) //将消息传送到指定窗口函数 励志照亮人生编程改变命运
LPCTSTR lpszTitle, //窗口标题名 DWORD dwStyle, //创建窗口的样式 int x,y, //窗口左上角坐标 int nWidth,nHeight, //窗口宽度和度高 HWND hwndParent, //该窗口的父窗口句柄 HWENU hMenu, //窗口主菜单句柄 HINSTANCE hInstance, //创建窗口的应用程序当前句柄 LPVOID lpParam, //指向一个传递给窗口的参数值的指针 ) 注意区分WNDCLASS中的style成员与CreateWindow()函数的dwStyle参数,前者是指定窗口类的 样式,基于该窗口类创建的窗口都具有这些样式,后者是指定某个具体的窗口的样式。 4. 显示及更新窗口 窗口创建之后,就可以调用函数ShowWindow()来显示窗口,该函数的原型如下: BOOL ShowWindow( HWND hWnd, int nCmdShow ); ShowWindow()函数有两个参数,第一个参数hWnd就是在上一步骤中成功创建窗口后返回的那个 窗口句柄;第二个参数nCmdShow指定了窗口显示的状态。 在调用ShowWindow()函数之后,紧接着调用UpdateWindow()函数来刷新窗口。UpdateWindow() 函数的原型如下: BOOL UpdateWindow( HWND hWnd); 其参数hWnd指的是创建成功后的窗口的句柄。UpdateWindow()函数通过发送一个WM_PAINT消 息来刷新窗口,UpdateWindow()函数将WM_PAINT消息直接发送给窗口过程函数进行处理,而没有 放到消息队列里。到此,一个窗口就算创建完成了。 2.2.3 消息循环 在创建窗口、显示窗口和更新窗口后,就需要编写一个消息循环,不断地从消息队列中取出消息, 并进行响应。要从消息队列中取出消息,需要调用GetMessage()函数,其原型如下: GetMessage (lpMSG, //指向MSG结构的指针 hwnd, //窗口句柄 nMsgFilteMin, //用于消息过滤的最小消息号值 nMsgFilterMax //用于消息过滤的最大消息号值 ) 只要从消息队列中取出消息不为WM_QUIT,GetMessage()函数就返回一个非零值,否则程序就 结束循环并退出。 通常编写的消息循环代码如下: MSG Msg; … while (GetMessage (&Msg,NULL,0,0)) { TranslateMessage(&Msg); //将消息的虚拟键转换为字符信息 DispatchMessage(&Msg); //将消息传送到指定窗口函数 } 34 励志照亮人生 编程改变命运 零基础学 Visual C++