第一章
This presentation is the property of its rightful owner.
Sponsored Links
1 / 92

第一章 Windows 编程基础知识 PowerPoint PPT Presentation


  • 84 Views
  • Uploaded on
  • Presentation posted in: General

第一章 Windows 编程基础知识. 1.1 Windows 操作系统的特点 1 直观的图形化用户界面 Windows 应用程序的外观是由诸如 窗口 、 菜单 、 工具栏 、 状态 栏 、 滚动条 、 对话框 等标准图形元素构成的。程序运行中的人 机交互操作也都是通过这些标准图形元素进行的。我们将这样 的用户界面称为图形化用户界面 GUI ( G raphics U ser I nterface )。 GUI 使得应用程序的用户界面统一、友好、美观。. 2 丰富的设备无关操作 Window 程序的输出显示均为图形操作(包括文本操作)。各

Download Presentation

第一章 Windows 编程基础知识

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Windows

第一章 Windows 编程基础知识


Windows

1.1 Windows 操作系统的特点

1 直观的图形化用户界面

Windows 应用程序的外观是由诸如窗口、菜单、工具栏、状态

栏、滚动条、对话框等标准图形元素构成的。程序运行中的人

机交互操作也都是通过这些标准图形元素进行的。我们将这样

的用户界面称为图形化用户界面 GUI(Graphics User Interface)。

GUI 使得应用程序的用户界面统一、友好、美观。


Windows

2 丰富的设备无关操作

Window程序的输出显示均为图形操作(包括文本操作)。各

类复杂的图形操作都是通过与物理设备无关的图形设备接口GDI

(Graphics Device Interface)完成的。每个图形操作都是在一个特

定的图形设备上下文(Device Context)中完成的。也就是说,通

过设备上下文句柄,能够调用图形设备接口 GDI所提供的相应

图形操作进行格式统一而具有特定功能的图形绘制操作,而这

些图形操作又可以通过对应的物理图设备驱动的支持,在指定

的设备上实现相应的图形输出。下图形象地示意了这种 GDI图

形接口的实现机制:


Windows

显示器驱动

打印机驱动

绘图仪驱动

GDI

虚拟设备


Windows

3 完善的多任务运行环境

Windows是一个多任务的操作系统。这种多任务表现在多个

不同进程(包括同一程序的多个进程实例)的同时运行和同一

进程中的多个线程的同时运行。这些同时运行的多任务对系统

资源的共享表现在:

CPU:通过系统分时实现多任务共享同一 CPU。

屏幕:通过可以重叠或平铺分布的窗口实现多个任务的视窗可

以共享同一屏幕,用户可以通过切换不同任务的窗口为活

动窗口,在不同任务之间进行切换。

内存:通过虚拟内存管理实现多任务共享有限的内存资源。多

任务之间可以进行手工和自动的数据交换和通信。


Windows

其中 Windows虚拟内存管理的实现如下:

⑴进程和内存空间

下面给出的图是在 Windows 95平台上,执行同一个 EXE 文

件的两个不同进程时的虚拟内存映射图。


Windows

0xFFFFFFFF

共享内存空间

0xC0000000

0x80000000

0x5F400000

0x10000000

堆栈

堆栈

可读/写全局内存

可读/写全局内存

0x00400000

进程A

硬盘

进程B

Windows

系统代码

Windows DLL

内存映射文件

MFC42.DLL

用户.DLL

交换文件

EXE文件


Windows

对于每个进程来说,只有低端的 2GB(0-0x7FFFFFFF) 的

地址空间是真正属于进程私有的。其中最低端的 4MB内存空间

是禁止访问的。进程运行期间所需要的堆栈、堆和可读/写的全

局内存以及应用程序的 EXE 文件和DLL文件都被映射到这 2GB

空间内。而高端的 2GB空间对所有的进程都是一样的,在这一

区间存放着所有进程共享的 Windows核心执行过程,虚拟设备

驱动程序(VxD)和文件系统代码以及一些重要的表(如映射页

表)都被映射到最高端1GB(0xC0000000 - 0xFFFFFFFF)空间中。

Windows DLL和内存映射文件在 0x80000000 - 0xBFFFFFFF 的内存

空间中。


Windows

由于低端的 2GB内存空间分配给特定的进程,所以一个进

程想要改变另一个进程的堆栈、全局内存或者堆空间的内容是

不可能的。

EXE和 DLL代码存放空间都有只读标记,因此,它们被映射

到多个进程是没有问题的。然而在最高端的 1GB空间有重要的

Windows可读数据,因此,这部分内存很容易受到错误程序的攻

击,例如毁坏系统表。在 0x80000000 - 0xBFFFFFFF地址空间中

存放的一个进程的映射文件也可能被另一个进程破坏。


Windows

在 Windows NT 中这些问题不会发生,因为在 Windows NT

中,进程只允许访问低端的 2GB空间,并且这 2GB的最高端和

最低端的 64KB空间是不允许访问的。同时高端的 2GB空间中

所存放的内容完全受保护。这就是为何提倡使用 Windows NT的

原因之一( Windows 2000 和 Windows XP 有类似的安全机制)。

⑵ 虚拟内存如何工作

① 为什麽要使用虚拟镜像技术

• 计算机不可能有数百个 GB的 RAM(物理内存)和数百个

GB的磁盘空间能满足多进程(每个进程 4GB)的需要。

• 每个进程的 4GB空间不会全部使用,更不会同时使用。


Windows

32位线性地址

位 31--22

位 21--12

位 11--0

每个进程拥有一个页表目录,它可以保存1024个页表地址

每个页表可保存1024个虚拟内存页地址

4096字节

32位地址

页表地址 标记

32位地址

页表地址 标记

20位

12位

20位

12位

CR3寄存器

Windows在CR3中为当前进程提供一个页表目录地址

② 如何实现虚拟镜像技术


Windows

• 32 位线性地址分三段,页表目录、页表和页内偏移量。

• 每页 4KB空间。

• 页以 4KB 为边界,即页的首地址必须是 4KB 的整倍数。

每个进程可以获得的虚拟内存空间为 4GB,每一个物理

地址的形成可以解析如下:

页表地址 = 页表目录地址+ 偏移量(第 22 - 31位),共

有1K 个页表。

页地址 = 页表地址+ 偏移量(地址第 12 - 21位),共有 1K*1K = 1M页。

物理地址 = 页地址 + 偏移量(地址第 0 - 11位),共有

1M*4KB = 4GB内存单元


Windows

• 每个页表入口都包含存在位(表示页是否在物理 RAM 中)

和读/写位(表示页中内容是否可读/写或只读)。

当需要访问此页内容时,根据“存在”位确定是否需要将此

页的内容从磁盘读入到此物理页中。如果页中内容有一段

时间未被访问,则根据虚拟管理的优化算法确定是否将页

中内容交换到磁盘中或直接放弃,使物理页空间可以被新

进程的页使用。在收回页面使用时,根据页的“读/写”位来

确定是将页中内容交换到磁盘中(例如,进程中所有可读

/写数据),或直接放弃(例如,程序 EXE代码和 DLL代

码,进程中的常量)。


Windows

③ 用户可以使用的内存操作函数

• 使用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);


Windows

• 使用GlobalUnlock 将内存空间解锁一次,LockCount–1,

当LockCount为0时,所分配的内存空间不再被锁定。

BOOL GlobalUnlock(HGLOBALhMem);

• 未锁定的内存地址(句柄)可以用GlobalFree 函数释放。HGLOBAL GlobalFree(HGLOBALhMem );

• 使用new分配内存空间。

• 使用delete释放由new 分配的内存空间。

• 内存映射文件:将一个地址范围直接映射到相应的文件。

当进程访问相应的内存页时,系统将分配 RAM,并从磁盘

中读入数据或将内存中数据写入磁盘,它可以用于进程间

共享。


Windows

•访问资源:资源是包含在 EXE 和 DLL代码中的,因此会

占用虚拟内存空间,而且这些空间在进程的生存期内是

不会被改变的,这就使得我们很容易读取一个资源。获

取资源的函数原型:

HGLOBAL LoadResource( HMODULE hModule,

HRSRC hResInfo);

参数:

hModule— 包含所取资源的模块句柄,NULL 表示从进程

中取资源。

hResInfo— 所取资源的句柄。

返回一个全局内存句柄HGLOBAL 可以安全地把它当作访

问存放资源的内存空间的索引。例如:


Windows

LPVOID lpvResource = (LPVOID)::LoadResource ( NULL,

::FindResource ( NULL,

MAKEINTRESOURCE(IDB_REDBLOCK),

RT_BITMAP ));

其中FindResource用于确定一个指定的资源位置,其原型:

HRSRC FindResource( HMODULE hModule, LPCTSTR lpName,

LPCTSTR lpType );

参数:

hModule — 包含所取资源的模块句柄,NULL 表示从进程中 取资源。


Windows

lpName— 所取资源的名字串。本例中是使用宏定义 MAKEINTRESOURCE 将资源标识 IDB_REDBLOCK

转换为资源名。

pType — 所取资源的类型。本例中使用的 RT_BITMAP表示

所取资源是一个位图资源。


Windows

4 灵活的消息处理机制

⑴ 队列化消息输入

Windows 操作系统将应用程序控制运行所需要各类信息以消

息的形式放在一个消息队列中,这个队列由操作系统管理。应

用程序只通过读取消息队列中的不同消息控制运行。

Windows 操作系统有一个系统消息队列,每个应用程序有一

个自己的消息队列,应用程序的消息来源:

①输入消息:如键盘、鼠标输入。这类消息通过系统消息

队列被送入应用程序消息队列。


Windows

②控件消息:用于与 Windows 的控件对象进行双向通信,

实现控件状态的变化。这类消息不通过系统消息队列,

可以通过应用程序消息队列,也可以直接发送到控件对

象上。

③系统消息:由系统管理事件(例如系统时钟)引起的消

息。这类消息中有些要通过系统消息队列送到应用程序

消息队列,如 DDE(Dynamic Data Exchange)消息;而另

一些消息直接送入应用程序消息队列,如创建窗口消息。

④用户消息:由程序员自己定义在应用程序中发出,并在

应用程序中响应处理的消息。这类消被直接送入应用程序消息队列。


Windows

⑵支持队列特征的消息驱动模型

Windows 操作系统主要包括三个基本内核元件:

①GDI(Graphics Device Interface):负责虚拟图形设备的操作,例如,屏幕绘图和打印。

②KERNEL:支持与操作系统密切相关的功能(如进程加载,文本切换,文件I/O,内存管理线程管理等)。

③USER:为所有的用户界面对象提供接收和管理所有输入

消息、系统消息,并把它们发给相应窗口的消息队列。


Windows

⑶事件驱动的程序设计

MS-DOS应用程序主要是采用顺序的、关联的、过程驱动的

程序设计方法。因此,过程的执行顺序是由程序直接控制,并

强制用户以某种不可更改的模式进行工作,交互性差。

Windows应用程序则是采用了由事件发生来控制程序运行逻

辑的设计方法,由于事件发生是随机的,没有预定的顺序,所

以用户就可以按照各种需要的、合理的顺序来安排程序的流程。

每个事件发生都会在对应的队列中放入一条消息。程序开始运

行后,总是从消息队列中读取消息等待事件的发生,并根据消

息做出相应的响应后,返回等待事件发生的状态,直至响应了

程序退出消息导致程序运行结束退出。


Windows

⑷ 支持应用程序间数据交换

Windows支持应用程序间通过以下途径进行数据交换:

① 动态数据交换 DDE(Dynamic Data Exchange),

② 剪切板(Clipboard),

③ 对象链接和嵌入 OLE(Object Linked and Embeded),

④组件对象模型 COM(Component Object Model)和分布式组件对象模型 DCOM(Distributed Component Object Model)。


Windows

5简便的动态链接库(DLL)应用

库是为应用程序提供各种功能和资源的最重要的途径,其中

动态链接库对于支持多任务的功能和资源共享和提高内存的使

用效率更为有效。Windows 平台为动态链接库的创建、安装和调

用提供了有效的支持,使得动态链接库的应用更加简便、可

行。所以动态链接库的开发和应用成为应用程序开发的重要手

段之一。


Windows

1.2Windows应用程序的特点

1事件驱动方式的程序设计模式

这种程序是由许多完成特定功能的子流程组成,在程序启动

运行之后,没有一个固定的执行流程,而是由用户的操作的结

果(事件)确定(驱动)子流程的执行,包括程序的结束。

2窗口程序设计模式

Windows 应用程序的基本单位不是过程和函数,而是窗口。

Windows 应用程序一般都具有标准的窗口界面风格。这个具有

标准风格的程序窗口界面都是由一系列的具有标准风格的界面

对象元素(如:窗口、图标、标题栏、菜单、工具栏、滚动

条、状态栏、对话框、控件、消息框等)组合而成的,例如

下图就是一个典型 Windows 程序的窗口界面。


Windows

3面向对象的程序设计模式

Windows 应用程序符合典型的面向对象结构的程序。程序为

用户提供的所有可视操作界面在程序内部都可视为一个 Windows

对象,用户对这些可视对象的操作通过事件驱动模式触发相应

Windows 对象的可调用方法。

Windows 程序的执行过程本身就是窗口和其他对象频繁创建、

处理和消亡的过程。程序执行过程中的消息发送可以理解为一

个窗口对象向别的窗口对象请求对象服务的过程。因此,用面

向对象的方法进行 Windows 程序设计与开发是极其方便、合理

的。


Windows

为了便于设计创建具有风格一致的窗口界面,微软公司在

Win32 函数库和 C++ 类库中为创建和操作上述标准界面元素提

供了大量的函数和 C++ 类。

学习和掌握有关这些标准界面元素的描述、创建的数据结

构和程序结构、C++ 类及其关系,是创建一个 Windows 程序的重

要基础之一,对于理解这些标准界面元素封装在类库中的类的

工作原理也是十分必要的,同时也有助于创建自己特殊风格的

界面元素以适应特定程序所需要的特定风格的界面。


Windows

4 资源共享

MS-DOS是单任务操作系统,DOS应用程序在运行时独占系

统的全部资源,如显示器、内存,在程序结束时才释放资源。

Windows 是一个多任务的操作系统,同时运行的各个应用程

序必须共享系统为程序运行提供的资源。系统资源是有限的,

如果使用资源的应用程序在资源使用完毕后不释放,就会造成

系统资源的枯竭,从而导致程序的运行异常,或干扰其他程序

的运行,甚至导致死机。因此 Windows 应用程序共享资源的基

本模式如下:

·向 Windows系统请求资源;


Windows

·使用资源;

·释放资源给 Windows,以供别的程序使用。

对于内存或其他硬件设备(键盘、鼠标、计数器、屏幕、

串/并接口等) 资源,一般不允许应用程序直接管理和访问,

而由 Windows 系统控制,以便向所有的应用程序提供公平的资

源,保证不中断的运行。如果应用程序确实需要对某些硬件进

行直接访问,则应当通过 Windows提供的特定 API函数实现安全

的访问。


Windows

5 程序和资源分开

在 DOS 程序中,界面设计编码工作和功能设计编码都是在

源程序中完成的。

在 Windows 应用程序中,实现界面的可视对象(如菜单、对

话框、位图等)都被从源程序中分离出来,放在资源文件(.rc)

中,并通过资源编译器将这些资源编译后,再链接到应用程序

的可执行文件或动态链接库文件中。程序与资源分离的优点:

⑴ 降低内存需求:资源可以不随着应用程序一起全部装入内

存,只有当这些资源被使用时才被装入自己的数据段,并不

驻留在应用程序的数据段;当内存紧张时,可废弃这些资源

(从内存中退出),待使用时再次自动装入。


Windows

⑵ 便于统一管理和重复利用

⑶ 应用程序与界面有一定的独立性,有利于软件的国际化


Windows

1.3Win32 程序结构

创建 Windows程序的方法有多种,最常用的方法是选择使用

WindowsAPI函数编程或 MFC编程。其中使用 MFC是完全遵照

面向对象程序设计的编程方法,是本课程的学习重点。而使用

Windows API编程对于理解 Windows程序的特点和运行机制更为

直观,因此,对于初学者首先从 Windows API编程入手是十分

必要的。

使用 Windows API编写的典型的 Windows应用程序是由主函

数和窗口函数两个基本部分组成:


Windows

1Windows 应用程序的主函数

主函数是 Windows 应用程序的入口,相当于控制台应用程序

中的 main函数。主函数名由系统确定,不允许改变。典型的主

函数中一般包括:

⑴定义主窗口类结构变量,并初始化;

⑵使用已经初始化的窗口类结构变量注册主窗口类别;

⑶创建已经成功注册的主窗口;

⑷显示并更新主窗口;

⑸启动消息循环,不断地接收消息,并分发到相应的窗口函数

去判断处理,直至收到关闭主窗口的消息,退出消息循环、

结束程序执行。


Windows

2窗口函数

窗口函数是由用户定义,由系统调用的回调函数。它的用途

是处理窗口消息,以完成程序需求的各种特定的功能。

在 Windows应用程序的运行过程中,通常总是先创建一个主

窗口,然后根据执行功能的需要,可能会有子窗口的创建和撤

消(如用于交互操作的对话框的创建和撤消)。每个窗口都应

有一个对应的窗口函数,用于处理对应窗口消息的响应操作,

因此,在一个 Windows应用程序中通常会有多个窗口函数,但

主窗口函数只有一个,换言之,Windows应用程序至少应有一个

主窗口函数。

主窗口函数必须在创建前通过主窗口类变量进行注册,而子

窗口函数一般是在主窗口函数中被注册、创建和撤消的。


Windows

1.3.1 定义窗口类的结构

窗口是一个具有标准风格的界面对象元素,它使用一个数

据结构来描述窗口样式、窗口消息处理函数、程序句柄、图标、

光标、背景刷、菜单以及描述本窗口类型结构的名称。根据这

个数据结构内容的描述,就可以创建一个具体的窗口。这个数

据结构的类型名为 WNDCLASS,定义如下:


Windows

typedef struct _WNDCLASS {

UINT style; // 窗口格式

WNDPROC lpfnWndProc; // 窗口函数指针

int cbClsExtra;// 窗口类结构变量后额外分配的字节数

int cbWndExtra;// 窗口实例后额外分配的字节数

HANDLE hInstance; // 窗口实例句柄

HICON hIcon; // 窗口图标句柄

HCURSOR hCursor;// 鼠标位置光标句柄

HBRUSH hbrBackground; // 窗口背景画刷句柄

LPCTSTR lpszMenuName; // 窗口菜单名字串指针

LPCTSTR lpszClassName; // 窗口类名字串指针

} WNDCLASS;


Windows

定义一个窗口类别结构变量,并初始化,例如:

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”;


Windows

扩展的窗口数据结构为 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;


Windows

1.3.2窗口类的注册与窗口创建、显示和更新

1窗口类的注册

定义一个窗口类结构变量,并初始化便确定了一个指定的窗

口。由于窗口的创建和窗口函数的回调操作都是由操作系统完

成的,因此,在该指定窗口创建之前,必须在系统中注册:通

过调用窗口类函数 RegisterClass 或 RegisterClassEx 用该窗口类

结构变量确定的窗口属性和其关联的主窗口函数。注册函数的

原型和调用实例如下:


Windows

⑴窗口类注册函数 RegisterClass

原型:

ATOM RegisterClass( CONST WNDCLASS *lpWndClass );

调用实例:

WNDCLASS wndcls;

if(!RegisterClass(&wndcls))

{

MessageBox(NULL, TEXT(“This program requires Windows!”), SzAppName, MB_ICONERROR);

return 0;

}


Windows

⑵窗口注册函数扩展版 RegisterClassEx

原型:

ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );

调用实例:

WNDCLASSEX wndcls;

if(!RegisterClassEx(&wndcls))

{

MessageBox(NULL, TEXT(“This program requires Windows NT!”), SzAppName, MB_ICONERROR);

return 0;

}


Windows

2窗口的创建

对于已经成功注册的窗口类,便可以调用窗口创建函数

CreateWindow 或 CreateWindowEx 在屏幕上显示所注册窗口类描

述的窗口并成为 Windows 应用程序的运行界面。窗口创建函数

的原型和调用实例如下:


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

);


Windows

调用实例:

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// 本窗口无须附加参数。

);


Windows

⑵窗口创建函数扩展版 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

);


Windows

调用实例:

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// 本窗口无须附加参数。

);


Windows

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索引的窗口,并以当前的

位置和尺寸显示窗口。


Windows

系统定义了一系列表示窗口显示状态值,祥见MSDN的有关

部分

BOOL UpdateWindow( HWND hWnd/* handle of window */ );

调用实例:UpdateWindow( hWnd );


Windows

1.3.3 启动消息循环

使所创建和显示窗口能够控制程序的运行,接收窗口消息并

做出相应的处理的关键是在 WinMain函数中启动一个消息循环。

正如在前面所述 Windows操作系统把所有驱动程序运行的事

件消息都放入应用程序消息队列,所以应用程序必须不断地从

消息队列中获取消息,并分发给相应的窗口函数,这就是消息

循环所要完成的工作,也是 Windows程序的一个重要特点。最

典型、最简单的消息循环定义如下:


Windows

MSG msg;

while (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

其中 MSG 定义了存放在消息队列中的每条消息的数据结构,其

定义如下:


Windows

typedef struct tagMSG

{

HWND hwnd; // 接收消息的目标窗口的句柄。

UINT message; // 窗口消息类别,其一般形式为 WM_XXX,如

// WM_PAINT, WM_CREATE, WM_TIMER等。

WPARAM wParam;

LPARAM lParam; // 这两个成员为 32位消息附加参数,它们的值

// 随着消息类别的不同而有所差异,例如消息

// WM_CLOSE,wParam和 lParam均为 0;消息

// WM_LBUTTONDOWN,wParam 表示鼠标按键

// 和键盘控制按键的状态,lParam 的低16 位和高

// 16 位分别表示鼠标单击点的 x和 y坐标。

DWORD time; // 消息置于消息队列的时间。

POINT pt; // 消息发生时鼠标在窗口中的坐标位置。

} MSG;


Windows

函数 GetMessage用于从消息队列中读取消息,其原型:

BOOL GetMessage( LPMSG lpMsg, HWND hWnd,

UINT wMsgFilterMin, UINT wMsgFilterMax );

参数:

lpMsg指向用于接收消息的结构变量。

hWnd指定消息所属窗口句柄,如为 NULL 表示将检索所有窗口的消息。

wMsgFilterMin指定消息检索范围下限值,0表示检索范围无下限值。

wMsgFilterMax指定消息检索范围上限值,0 表示检索范围无上限值。


Windows

返回:

·如果检索到的消息不是 WM_QUIT消息,则返回非0;

·如果检索到的消息是 WM_QUIT消息,则返回0;

·如果发生错误,例如参数 lpMsg和/或 hWnd非法,则返回

-1。使用函数 GetLastError可以获得进一步的错误信息。

·当函数发现消息队列为空时,进程被阻塞,这时进程可交

出 CPU控制权,从而让出 CPU时间片给别的进程。


Windows

函数 TranslateMessage用于将来自键盘的命令翻译成 WM_XXX

形式的命令,该函数原型:

BOOL TranslateMessage( CONST MSG *lpMsg );

参数:

lpMsg — 指向消息结构变量。

返回:

如果消息被翻译,则返回非0。


Windows

函数 DispatchMessage用于将检索到的消息分送到相应的窗口

函数。注意,应用程序并不直接调用窗口函数,而由系统根

据消息调用相应的窗口函数,所以窗口函数称为回调函数。

该函数的原型:

LONG DispatchMessage( CONST MSG *lpMsg );

参数:

lpMsg — 指向消息结构变量。

返回:

表明相应的窗口函数的返回值,虽然该值反映了被分派消息

的响应情况,但往往被忽略。


Windows

1.3.4 窗口主函数 WinMain

综前所述,Windows 应用程序的主函数 WinMain的声明如下:

int WINAPI WinMain(

HINSTANCE hInstance, // handle to current instance

HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // pointer to command line

int nCmdShow// show state of window

);

WinMain函数的典型定义包括主窗口的定义和初始化,注册,

创建,显示和更新,启动消息循环五部分。如下所示:


Windows

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

static TCHAR szAppname[ ] = TEXT(“HelloWin”);

HWNDhWnd;

MSGmsg;

// 定义窗口,并初始化

WNDCLASSwndclass;

wndclass.style= CS_HREDRAW|CS_VREDRAW;

wndclass.lpfnWndProc= WndProc;

wndclass.cbClsExtra= 0;

wndclass.cbWndExtra= 0;

wndclass.hInstance= hInstance;


Windows

wndclass.hIcon= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackgound= (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName= NULL;

wndclass.lpszClassName= szAppName;

// 注册已经定义的窗口

if(!RegisterClass(&wndclass)) {

MessageBox(NULL, TEXT(“This program requires Windows NT!”), SzAppName, MB_ICONERROR);

return 0;

}


Windows

// 创建已经成功注册的窗口

hWnd = CreateWindow ( szAppname, TEXT(“The Hello Program”), CW_USERDEFAULT,

CW_USERDEFAULT,CW_USERDEFAULT,

CW_USERDEFAULT,

NULL,

NULL,

HInstance,

NULL);


Windows

// 显示并更新已经创建的窗口

ShowWindow(hWnd, iCmdShow);

UpdateWindow(hWnd);

// 建立消息循环

While(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}


Windows

1.3.5 窗口函数 WndProc和消息处理

Window 应用程序的窗口函数 WndProc的原型声明如下:

LRESULT CALLBACK WndProc( HWND hWnd, UINT message,

WPARAM wParam, LPARAM lParam );

其中:

·LRESULT表示函数的返回类型,与长整型等价。该函数返回值由调用它的系统使用。

·CALLBACK表示该函数是回调函数,即该函数由系统调用。

参数:

·hWnd — 接收消息的目标窗口的句柄;

·message — 消息类别;


Windows

·wParam和 lParam — 32 位消息附加信息参数。

由于主窗口函数 WinProc在主窗口类结构变量定义时,与主

窗口关联,所以由主窗口类创建的主窗口就是应用程序的主界

面,使得消息通过主函数的消息循环,被分发给与该主窗口相

关联的窗口函数。例如,一个典型的主窗口函数 WndProc定义

如下:


Windows

LRESULT CALLBACK WndProc( HWND hwnd, UINT message,

WPARAM wParam, LPARAM lParam )

{

HDChdc; // 设备上下文句柄,用于窗口中的绘图和文本输出。

PAINTSTRUCT ps;// 用于保存绘图场境的结构变量。

RECTrect; // 用于保存矩形区域信息的结构变量。

switch( message ){

case WM_PAINT:

hdc = BeginPaint( hwnd, &ps );// 获取绘图场境。

GetClientRect( hwnd, &rect );// 获取绘图区域。

DrawText( hdc, TEXT( “Hello Windows 98!” ), -1, &rect,

DT_SINGLELINE|DT_CENTER|DT_VCENTER );

// 在窗口中央绘制一行文本。

EndPaint( hwnd, &ps );// 释放绘图场境。

return 0;


Windows

case WM_DESTROY:

PostQuitMessage(0);// 寄送退出消息。

return 0;

}

return DefWindowProc( hwnd, message, wParam, lParam );

// 窗口消息的缺省处理。

}


Windows

其中:

① 函数 BeginPaint用于获取窗口的设备上下文,并保存在

lpPaint指向的变量中,该函数原型声明如下:

HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint );

参数:

·hwnd — 设备环境所属窗口的访问句柄。

·lpPaint — 指向存放绘图信息的结构变量。


Windows

② 函数 GetClientRect 用于获取窗口客户区的大小信息并保存

lpRect指向的变量中,其原型如下:

BOOL GetClientRect( HWND hWnd, LPRECT lpRect );

参数:

·hWnd — 矩形区域所属窗口的访问句柄。

·lpRect — 存放矩形区域信息的结构变量地址。


Windows

③ 函数 DrawText通过使用由 hdc指定的绘图工具和绘图属

性,在 lpRect指定的矩形区域中输出文本“Hello, Windows

98!”,该函数原型声明如下:

int DrawText( HDC hdc, LPCTSTR lpString, int nCount,

LPRECT lpRect, UINT uFormat );

参数:

·hdc — 设备环境的访问句柄。

·lpString— 指向要绘制的文本。

·nCount — 文本的字节长度。

·lpRect — 指向绘制字符串的窗口矩形区域


Windows

·uFormat — 文本的绘制标志。

本例中调用该函数的参数 nCount = -1 表示输出文本串以

null结尾;

参数 uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER

表示文本绘制风格为:单行输出,并在 lpRect指定的矩形

区域中水平和垂直都居中对齐。


Windows

④ 函数 EndPaint与 BeginPaint配对使用,以便在使用完 hdc

后,立刻释放设备环境资源,该函数的原型声明如下:

BOOL EndPaint( HWND hWnd, CONST PAINTSTRUCT *lpPaint );

参数:

·hWnd — 窗口访问句柄。

·lpPaint — 指向存放绘制信息的结构变量。

⑤ 函数 PostQuitMessage用于在应用程序消息队列中放入一

个 WM_QUIT消息,以便 GetMessage得到此消息时,终

止消息循环和应用程序。该函数原型声明如下:

VOID PostQuitMessage( int nExitCode/*exit code */);


Windows

⑥ 函数 DefWindowProc用于完成系统的默认处理。其原型声

明如下:

LRESULT DefWindowProc( HWND hWnd, UINT Msg,

WPARAM wParam, LPARAM lParam );

参数:

·hWnd —窗口访问句柄。

·Msg — 消息标识。

·wParam — 消息的第一附加参数。

·lParam — 消息的第二附加参数。


Windows

从上述分析可以在以下几个方面归纳窗口函数的特点:

⑴ 窗口函数的作用是处理由消息循环发送来的各类消息。

⑵ 窗口函数是回调函数,即由系统通过消息调用。

⑶ 窗口函数名可以随意定义。

⑷ 程序中的每一个窗口(响应处理某些消息)必须有一个对应

的窗口函数。

⑸ 一个程序中可以有多个窗口函数,但主窗口函数只能有一

个,该窗口函数必须通过主窗口类的定义和注册与主窗口相

关联。


Windows

1.3.6资源定义文件

在 Windows应用程序中,除了主函数和窗口函数外,通常还

需要定义应用程序中需要的资源。资源包括应用程序所能够使

用的一类预定义资源中的一个对象,例如,字符串资源、加速

键表、菜单、工具栏、对话框、位图、光标、图标、版本信息

和用户自定义资源等。

在 Windows程序设计中,全部资源都被单独分离出来放在扩

展名为 .rc的资源文件中。在编译过程中,该资源文件经资源编

译器编译后,生成 .res二进制资源文件。在程序的链接过程

中, .res将与 .obj文件一起链接成可执行文件 .exe。


Windows

1.4Win32程序开发流程

Win32 程序的开发应包括如下过程:

⑴ 定义应用程序用到的资源(产生资源描述文件)。

⑵ 定义应用程序的源程序,主要包括:

① 定义 WinMain 函数,该函数需要做以下事情:

·定义窗口类;

·注册窗口类;

·创建窗口;

·显示并更新窗口;

·启动消息循环。

② 定义窗口函数。

⑶ 编译、链接源程序和资源文件。


Windows

1.5生成一个典型 Win32 窗口程序

1 在 Visual C++ 6.0集成开发环境中

⑴ 使用 AppWizard 生成一个名为 “MyWin”的 Win32 Application

窗口程序项目

⑵查看项目的目录和相应的主要文件。

⑶查看和分析源程序中关键代码。

⑷查看和分析资源文件中定义的资源。

⑸编译、链接并运行程序。


Windows

2 在 Visual C++ .NET集成开发环境中

⑴ 使用 AppWizard 生成一个名为 “MyWin”的 Win32 Project程序

项目。

⑵查看项目的目录和相应的主要文件。

⑶查看和分析源程序中关键代码。

⑷查看和分析资源文件中定义的资源。

⑸编译、链接并运行程序。


Windows

1.6介绍 Visual C++ 集成环境

1使用 AppWizard 生成各类新项目(包括向已建项目中加入各类

文件)包括:

ATL COM AppWizard

MFC AppWizard(DLL)

MFC AppWizard(EXE)

MFC ActiveX Control Wizard

Win32 Application

Win32 Console Application

Win32 Dynamic-Link Library

Win32 Static Library


Windows

2使用 Workspace查看和编辑工程项目内容

使用 ClassView查看和编辑(增加新类、增加/删除/修改类成员

等)工程的类。

使用 ResourceView查看和编辑资源文件,这些资源包括:

·加速键(Accelerator)

·位图(Bitmap)

·光标(Cursor)

·对话框(Dialog)和对话框中安放的各类控件(Controls)

·图标(Icon)

·菜单(Menu)

·字符串表(String Table)

·工具栏(Toolbar)


Windows

使用 FileView查看和编辑组成工程的各类程序源文件,这些源文

件类包括:

·实现代码源文件(Source Files)

·定义代码头文件(Header Files)

·资源代码源文件(Resource Files)

·外部依赖文件(External Dependencies)

3编译、连接和运行:

由Build 菜单提供全部编译、连接和运行操作:

⑴编译单个代码源文件(Compile xxx.cpp Ctrl+F7)

⑵ 创建工程的可执行文件(Build xxx,exe F7)

⑶重新创建工程编译、连接过程中产生的全部文件(Rebuild

All)


Windows

  • ⑷批创建调试版本和/或发布版本的可执行文件或编译、连接

  • 的全部文件(Batch Build)

  • ⑸清除当前的编译、连接结果(Clean)

  • ⑹调试(Start Debug)调试方式包括:

  • ·断点调试运行(Go F5)遇到设置断点或错误点暂停,使

  • 用功能键 F9设置/取消单个断点,Ctrl+shift+F9 取消全部断

  • 点。

  • ·单步调试运行(Step Into…F11)

  • ·运行到当前光标处(Run to CursorCtrl+F10)

  • 4使用 MSDN 寻求帮助,查询方式:

    • 按内容查询(Contents)

    • 搜寻关键词(Search…)

    • 索引查询 (Index…)

    • 键盘映射 (Keybaod Map)


Windows

.h

.cpp

.rc

.obj

.res

.exe

5工程项目中包括的主要子目录、文件类型和工作流程:

子目录:Debug, Release, Res。注意,Res子目录不能被删

除。文件类型:dsp,dsw,h,cpp,pch,res,obj,ncb,clw

等。

注意,其中 dsp, h, cpp类型文件不能被删除;ncb, clw类型文

件只有在 MFC应用程序项目中才有。编制 windows应用程序的

工作流程如下:

文本编辑

资源编辑

C++编译

资源编译

链接


Windows

1.7 介绍 Visual C++.NET 集成环境

1 介绍 .NET

⑴.NET的概念

.NET 的目标是搭建第三代因特网平台,建立平台的运行规

则,在平台上解决网站之间的协作,最大限度地获取信息。

在 .NET 平台上,通过相关的协定,不同网站被联系在一

起,自动交流、协同工作,从而提供最全面的服务。使因

特网成为 IT产业和世界经济发展促进因素的必然方向。

为此,.NET 的核心目标就是对现有的计算模式和软件开发

方式进行有针对性的调整,使之符合第三代因特网运营的

需要,所以我们应该把 .NET 理解为一种新技术、新理念。


Windows

⑵.NET Framework

为了这种新技术、新理念,就需要为软件开发人员提供一个开发平台—— .NET Framework,使应用程序的开发更为

简单。 .NET Framework 是一个可以构造、发布并运行 Web

服务的开发环境。它代表了一种崭新的软件开发模式,与

API或 COM一样都是把系统服务以接口的形式提供给开发

人员;而不同之处在于, .NET Framework 能更好地完成代

码的重用、资源配置、多语言集成开发和安全管理等任

务,在安全性、易用性和开发效率方面都远远超过以前的

开发模式。 .NET Framework 主要包括以下一些特点:


Windows

·提供了面向对象的交叉语言类库

.NET Framework 的主要组件之一,基类库(Base Class

Library)为所有编程语言提供一致、面向对象的类集,从

而避免了开发人员由于使用不同语言的类库而必须进行

的切换,大大降低了多语言集成开发的复杂程度。

·应用程序一次运行就会永远运行

.NET Framework 通过内部跟踪每个应用程序运行所需要的

文件及其版本号,从而解决了由于安装新组件覆盖了应

用程序运行依赖的组件所引起的 “DLL灾难(DLL hell)”问题。


Windows

·一致的运行环境

运行时(Runtime)是 .NET可执行程序唯一的运行环境,

从而保证了在一个 .NET 版本下编译链接并运行的应用程

序可以运行在 .NET 的所有版本下。

·通用的类型系统

.NET Framework 定义了通用类型系统(CTS),其中定义

了 .NET 所支持的全部类型以及实例化和管理这些类型的

方法。使得不同的语言可以访问相同的类型,而无须在

每种语言支持的类型之间来回转换数据,同时运行时的

类型控制权又确保了将正确的参数个数和类型传递给指定方法。


Windows

·集成的编程语言

.NET Framework 中的所有语言必须遵守一个统一的标准,

使得用不同语言代码之间的集成比以前更加容易。

·内存和资源的自动管理

.NET平台的运行时引擎可以自动跟踪应用程序的资源使

用情况,并确保不会出现资源泄漏。

·统一的异常处理

在 .NET平台上,所有的错误处理都通过异常来报告,并

且异常处理也可以跨越语言边界,这就使得开发人员可

以从代码中除去那些复杂的对可能发生的错误的判断,

使代码的编写、阅读和维护工作大大简化。


Windows

·大大简化了应用程序的发布

在 .NET平台上,安装软件意味着直接将应用程序拷贝到

机器上即可,而卸载应用程序只要删除它们就可以了,

而不必为应用程序编写特定的安装和卸载程序。

·先进的安全机制

.NET平台的安全机制的核心是一种信任机制,即如果应

用程序是来自可信任的物理介质(如 CD-ROM)或服务器,则是可信任;否则(来自不明的 Web、因特网下载或 E-mail 附件)都会使用代码的安全机制来进行控制。


Windows

2Visual C++.NET的开发范围

Visual C++.NET 与 Visual C++ 相比较,有许多新特征,其中

最重要、最显著的特征表现在:

·集成性和易用性等各个方面都有了大幅度的提高

·开发范围发生了重要变化,包括了托管(managed)应用和

非托管(unmanaged)应用两部分。

⑴托管(managed)应用

所谓托管应用是使用 .NET Framework 的SDK 来编写托管

C++语言的应用程序,这类应用可以具有 .NET Framework 的

所有特点。


Windows

托管 C++语言是对传统 C++语言的扩充,它对基本语法没

有任何更改,而我们原来熟知的传统类型发生了很多变化。

因此,编写这类应用不但需要熟悉传统的 C++语言,还需

要熟悉托管 C++语言。需要开发托管应用的需求如下:

·需要将传统的 C++应用程序合并到 .NET Framework 中

由于托管扩展可以实现托管和非托管两种类型的代码的

无缝平滑转换,所以在应用程序中,甚至同一文件中可

以混合使用两种类型的代码。这就使得开发人员可以继续使用传统的 C++应用程序功能,为了让 .NET Framework

应用程序顺利访问这些功能,编写一个很小的、转换效

率很高的包装(wrapper)程序。


Windows

·使任何与 .NET Framework 相容的语言可以访问 C++组件

托管扩展可以编写简单的托管包装类用于对访问方(映

射)公开被访问的 C++类和方法。这就使得从任何一种

与 .NET Framework 相容的语言编写的应用程序中通过调

用托管包装类和方法实现对 C++组件的访问成为可能。

特别需要指出,托管扩展支持对非托管 DLL 的调用。

·需要从传统的 C++应用程序中访问 .NET Framework 类

使用托管扩展,可以在传统 C++应用程序中直接创建、

调用一个 .NET Framework 类,并且可以像处理普通 C++

类一样对待托管类的处理。这就使得在 .NET 平台上开

发、运行的传统 C++应用程序可以获得更多的功能。


Windows

⑵ 非托管(unmanaged)应用

非托管应用是通过 Win32SDK,在微软基类库(MFC)的基础上,利用传统的 C++ 语言来编写的标准 Win32 应用程序。

保留非托管应用开发模式的主要原因是传统的 Visual C++ 具有发展历史长、开发范围、应用程序运行效率高、开发技术成熟。在那些对软件使用效率要求高的场合,如图象处理、音频处理、文字处理等,几乎成了世界级厂商进行开发工作的首选。至少就目前软、硬件水平的发展来看,使用托管类编写的 .NET 应用程序与使用编写的应用程序的运行效率是无法相提并论的。所以,无论从保障已有投资还是保证应用程序工作效率的角度来讲,传统的 Visual C++ 开发模式和主要支持库 MFC 都仍然具有强大的生命力。


Windows

不难看出,托管应用和非托管应用各有优点,因此在实际

开发工作中,开发人员可以根据项目的实际需求,灵活选择

两类应用的使用。在某些追求运行效率和性能的情况下,采

用非托管模式开发可以获得较好的效果;而在某些需要快速

完成开发任务,特别是需要充分使用 .NET平台提供网络功能

的情况下,采用托管模式开发更为适宜;在上述两种需求兼

有的复杂情况下,采用托管和非托管的混合模式开发,使两

类代码无缝转化连接可以较好地达到预期的效果。


  • Login