第三章 Win32应用程序设计Word格式文档下载.docx

上传人:b****5 文档编号:20344110 上传时间:2023-01-22 格式:DOCX 页数:34 大小:72.77KB
下载 相关 举报
第三章 Win32应用程序设计Word格式文档下载.docx_第1页
第1页 / 共34页
第三章 Win32应用程序设计Word格式文档下载.docx_第2页
第2页 / 共34页
第三章 Win32应用程序设计Word格式文档下载.docx_第3页
第3页 / 共34页
第三章 Win32应用程序设计Word格式文档下载.docx_第4页
第4页 / 共34页
第三章 Win32应用程序设计Word格式文档下载.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

第三章 Win32应用程序设计Word格式文档下载.docx

《第三章 Win32应用程序设计Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《第三章 Win32应用程序设计Word格式文档下载.docx(34页珍藏版)》请在冰豆网上搜索。

第三章 Win32应用程序设计Word格式文档下载.docx

Windows应用程序是事件驱动(或称作消息驱动)的应用程序。

Windows是一个多任务的操作系统,也就是说,在同一时刻,在Windows中有着多个应用程序的实例正在运行,比如说这时我正在打开字处理软件Word来编写这本书的书稿,同时,还打开了VisualC++的集成开发环境MicrosoftDeveloperStudio来调试书中的示例程序,而且,后台还在放着歌曲。

在这样的一个操作系统中,不可能像过去的DOS那样,由一个应用程序来享用所有的系统资源,这些资源是由Windows统一管理的。

那么,特定的应用程序如何获得用户输入的信息呢?

事实上,Windows时刻监视着用户的一举一动,并分析用户的动作与哪一个应用程序相关,然后,将用户的动作以消息的形式发送给该应用程序,应用程序时刻等待着消息的到来,一但发现它的消息队列中有未处理的消息,就获取并分析该消息,最后,应用程序根据消息所包含的内容采取适当的动作来响应用户所作的操作。

举一个例子来说明上面的问题,假设我们编了一个程序,该程序有一个File菜单,那么,在运行该应用程序的时候,如果用户单击了File菜单,这个动作将被Windows(而不是应用程序本身!

)所捕获,Windows经过分析得知这个动作应该由上面所说的那个应用程序去处理,既然是这样,Windows就发送了个叫做WM_COMMAND的消息给应用程序,该消息所包含的信息告诉应用程序:

“用户单击了File菜单”,应用程序得知这一消息之后,采取相应的动作来响应它,这个过程称为消息处理。

Windows为每一个应用程序(确切地说是每一个线程)维护了相应的消息队列,应用程序的任务就是不停的从它的消息队列中获取消息,分析消息和处理消息,直到一条接到叫做WM_QUIT消息为止,这个过程通常是由一种叫做消息循环的程序结构来实现的。

Windows所能向应用程序发送的消息多达数百种,但是,对于一般的应用程序来说,只是其中的一部分有意义,举一个例子,如果你的应用程序只使用鼠标,那么如WM_KEYUP、WM_KEYDOWN和WM_CHAR等消息就没有任何意义,也就是说,应用程序中事实上不需要处理这些事件,对于这些事件,只需要交给Windows作默认的处理即可。

因此,在应用程序中,我们需要处理的事件只是所有事件中的一小部分。

图3.1给出了一般Windows应用程序的执行流程。

图3.1Windows应用程序的基本流程

因此,从某种角度上来看,Windows应用程序是由一系列的消息处理代码来实现的。

这和传统的过程式编程方法很不一样,编程者只能够预测用户所利用应用程序用户界面对象所进行的操作以及为这些操作编写处理代码,却不可以这些操作在什么时候发生或者是以什么顺序来发生,也就是说,我们不可能知道什么消息会在什么时候以什么顺序来临。

Windows程序在处理消息时使用了一种叫做回调函数(callbackfunction)的特殊函数。

回调函数由应用程序定义,但是,在应用程序中并没有调用回调函数的代码,回调函数是供操作系统或者其子系统调用的,这种调用通常发生在某一事件发生,或者在窗口或字体被枚举时。

典型的回调函数有窗口过程、对话框过程和钩子函数。

其中的窗口过程和对话框过程将在本章后面的内容中讲述。

第二节Win32API和SDK

说到Windows编程,就不能不谈到WindowsAPI(WindowsApplicationProgrammingInterface,Windows应用程序编程接口),它是所有Windows应用程序的根本之所在。

简单的说,API就是一系列的例程,应用程序通过调用这些例程来请求操作系统完成一些低级服务。

在Windows这样的图形用户界面中,应用程序的窗口、图标、菜单和对话框等就是由API来管理和维护的。

WindowsAPI具有两种基本类型:

Win16API和Win32API。

两者在很多方面非常相像,但是Win32API除了几乎包括了Win16API中的所有内容以外,还包括很多的其它内容。

WindowsAPI依靠三个主要的核心组件提供Windows的大部分函数,在Win16和Win32中,它们具有不同的名称,如表3.1所示。

Win16API

Win32API

说明

USER.EXE

USER32.DLL

负责窗口的管理,包括消息、菜单、光标、通信、计时器和其它与控制窗口显示

GDI.EXE

GDI32.DLL

提供图形设备接口,管理用户界面和图形绘制,包括Windows元文件、位图、设备描述表和字体等

KRNL386.EXE

KERNEL32.DLL

处理存储器低层功能、任务和资源管理等Windows核心服务

表3.1Win16和Win32的核心组件

虽然Win16API组件带有.EXE的扩展名,但是它们事实都是动态链接库(.DLL),不能单独运行。

其它一些非核心的WindowsAPI由其它组件所提供的DLL来实现,这些组件包括通用对话框、打印、文件压缩、版本控制以及多媒体支持等。

WindowsSDK(WindowsSoftwareDevelopmentKit,Windows软件开发工具包)和WindowsAPI紧密联系,它是一套帮助C语言程序员创建Windows应用程序的工具,在WindowsSDK中包括了以下几个组成部分:

l大量的在线帮助,这些帮助描述了Windows编程所可能用到的函数、消息、结构、宏及其它资源

l各种编程工具,如对话框编辑器及图象编辑器等

lWindows库及头文件

l使用C语言编写的示例程序

该工具包的最新版本就是我们正在使用的Win32SDK,在安装了VisualC++的同时,Win32SDK也安装到你的计算机上了。

尽管MFC提供了对Win32API的比较完整的封装,但是,在某些情况下,我们更倾向于直接调用Win32API,因为这有时候可以获得更高的效率,并且有着更大的自由度。

而且,使用MFC编写的新风格的Windows应用程序的工作方式基本上与使用SDK编写的同一程序一样,它们往往有着很多的共同之处,只是使用MFC更加的方便,因为它隐藏了大量的复杂性。

前面提到过,面向对象的编程方式是当前最流行的程序设计方法,但是,Win32API本身却是基于C语言的过程式编程的,SDK和MFC的最主要的不同之处也就是以C与C++之间的差别,使用MFC进行Windows应用程序设计需要面向对象的编程思想和方法,好在我们已经在前面这此进行了大量的铺垫。

第三节使用SDK编写Windows应用程序

传统的DOS程序以main函数作为进入程序的初始入口点,在Windows应用程序中,main函数被WinMain函数取而代之,WinMain函数的原型如下:

intWINAPIWinMain(HINSTANCEhInstance,//当前实例句柄

HINSTANCEhPrevInstance,//前一实例句柄

LPSTRlpCmdLine,//指向命令行参数的指针

intnCmdShow)//窗口的显示状态

这里出现了一个新的名词“句柄”(handle),所谓的句柄是一个标识对象的变量,或者是一个对操作系统资源的间接引用。

在上面的函数原型中,我们看到了一些“奇怪”的数据类型,如前面的HINSTANCE和LPSTR等,事实上,很多这样的数据类型只是一些基本数据类型的别名,表3.2列出了一些在Windows编程中常用的基本数据类型的别名,表3.3列出了常用的预定义句柄,它们的类型均为void*,即一个32位指针。

表3.2Windows基本数据类型

Windows的数据类型

对应的基本数据类型

BOOL

Int

布尔值

BSTR

unsignedshort*

32位字符指针

BYTE

unsignedchar

8位无符号整数

COLORREF

unsignedlong

用作颜色值的32位值

DWORD

32位无符号整数,段地址和相关的偏移地址

LONG

Long

32位带符号整数

LPARAM

作为参数传递给窗口过程或回调函数的32位值

LPCSTR

constchar*

指向字符串常量的32位指针

LPSTR

char*

指向字符串的32位指针

LPCTSTR

constchar*(注1)

指向可移植的Unicode和DBCS字符串常量的32位指针

LPTSTR

char*(注1)

指向可移植为Unicode和DBCS字符串的32位指针

LPVOID

void*

指向未定义类型的32位指针

LRESULT

来自窗口过程或回调函数的32位返回值

UINT

unsignedint

32位无符号整数

WNDPROC

long(_stdcall*)(void*,

unsignedint,unsignedint,long)(注2)

指向窗口过程的32位指针

WORD

unsignedshort

16位无符号整数

WPARAM

unsignedint

当作参数传递给窗口过程或回调函数的32位值

注1:

这是在DBCS版本下的情况,在Unicode版本下LPCTSTR和LPTSTR将代表其它的数据类型。

注2:

事实上,WNDPROC被定义为LRESULT(CALLBACK*)(HWND,UINT,WPARAM,LPARAM),这个定义最终被编译器解释为long(__stdcall*)(void*,unsignedint,unsignedint,long)。

表3.3Windows公用句柄类型

句柄类型

HBITMAP

保存位图信息的内存域的句柄

HBRUSH

画刷句柄

HCTR

子窗口控件句柄

HCURSOR

鼠标光标句柄

HDC

设备描述表句柄

HDLG

对话框句柄

HFONT

字体句柄

HICON

图标句柄

HINSTANCE

应用程序的实例句柄

HMENU

菜单句柄

HMODULE

模块句柄

HPALETTE

颜色调色板句柄

HPEN

在设备上画图时用于指明线型的笔的句柄

HRGN

剪贴区域句柄

HTASK

独立于已执行任务的句柄

HWND

窗口句柄

查看Win32SDK文档或者浏览Windows头文件(如windef.h、ctype.h以及winnt.h等)可以获得关于其它数据类型的定义,这些定义往往使用了#define和typedef等关键字。

这里解释什么是应用程序的一个实例(instance)。

最简单的理解可以用下面的例子来说明:

比如说已经在Windows中打开了一个“写字板”(可以在“开始”菜单中的“程序|附件”下面找到它的快捷方式),现在你需要从另一篇文章里复制一部分内容到你正在写的这篇文章中,那么,你可以再打开一个“写字板”(注意写字板不是一个多文档应用程序,不能像在Word中那样打开多个不同的文件),然后从该写字板中复制文件的内容到在前一个写字板内打开的文章中。

这里,我们多次运行了同一个应用程序,在这个例子中,我们将所打开的两个写字板叫做该应用程序的两个实例。

对于实例的更精确(当然也要比上面的例子要更难懂得多)的定义,在Win32SDK中是这样给出的:

实例就是类中一特定对象类型的一个实例化对象(instantiation),如一个特定的进程或线程,在多任务操作系统中,一个实例指所加载的应用程序或动态链接库的一份拷贝。

刚开始时我们也许看不懂这一定义,不过没有关系,慢慢的就理解了。

l注意:

l尽管在前面给出的WinMain函数的原型中包括了一个名为hPrevInstance的HINSTANCE类型的参数,按照其字面上的意义,它所传递的是应用程序的前一个实例的句柄,但是,在Win32平台下,该参数的值总是为NULL,而不管是否有当前应用程序的实例在运行。

在过去的Windows3.x环境下编程,我们常常使用下面的代码来检查应用程序是否已有一个实例在运行:

lif(!

hPrevInstance)

l{

l//在此添加没有应用程序实例在运行时的所需执行的代码。

l//对于大多数应用程序,我们常在这里注册窗口类。

l}

然而,在Win32操作系统——Windows95、WindowsNT以及其后续版本中,上面的if条件体中的代码总会被执行,因为hPrevInstance总是为NULL,因此!

hPrevInstance恒为真。

之所以这样,是因为在Win32环境下,每一个应用程序的实例都有自已独立的地址空间,因此,它们之间互相独立,互不干涉。

但是,对于一些应用程序,只需要而且只应该有一个实例在运行。

什么情况下会是这样呢?

假设我们编写了一个应用程序,在默认情况下,该应用程序将在后台运行,通过按下程序所定义的某一个热键,应用程序将被激活。

对于这样的应用程序,在同一时该只应该有一个实例在运行。

另外,像WindowsNT下在任务管理器,在同一时刻也只可以有一个实例在运行。

使用下面的技巧可以保证在同一时刻只有应用程序的一个实例:

l#include"

windows.h"

l

l#defineVK_X0x58

lintWINAPIWinMain(HINSTANCEhInstance,

lHINSTANCEhPrevInstance,

lLPSTRlpCmdLine,

lintnCmdShow)

CreateMutex(NULL,TRUE,"

NoPreviousInstance!

"

))

lMessageBox(NULL,"

创建Mutex失败!

"

NoPrev"

MB_OK|MB_SYSTEMMODAL);

lreturnFALSE;

lif(GetLastError()==ERROR_ALREADY_EXISTS)

已有NoPrev的一个实例在运行,当前实例将被终止!

l"

lif(!

RegisterHotKey(NULL,0x0001,MOD_CONTROL|MOD_SHIFT,VK_X))

注册热键Ctrl+Shift+X失败!

NoPrev已启动!

\n\n按下热键Ctrl+Shift+X将终止NoPrev."

lMSGmsg;

lwhile(GetMessage(&

msg,NULL,0,0))

lswitch(msg.message)

lcaseWM_HOTKEY:

lif(int(msg.wParam)==0x0001)

lif(MessageBox(NULL,"

终止NoPrev?

MB_YESNO|MB_SYSTEMMODAL)==IDYES)

lreturnTRUE;

上面的代码是一个功能完整的Windows应用程序,其中用到了一些到目前为止我们还未讲述到的内容。

程序定义了热键Ctrl+Shift+X,当按下该热键时将终止该程序。

由于程序中没有包括任何窗口,因此这是唯一的一种正常终止应用程序的方法。

当程序NoPrev正在后台运行时,如果用户按下了组合键Ctrl+Shift+X,Windows将向程序主线程的消息队列中发送一条称为WM_HOTKEY的消息,当程序收到这条消息时,即弹出了消息框询问是否终止NoPrev。

上面的说明将有助于你理解以上代码,但是我们目前对止并不做要求。

这里,只需要注意下面的代码:

在上面的代码中,我们先调用CreateMutex创建一个名为“NoPreviousInstance”的命名互斥对象(namedmutexobject),如果该对象名已存在(注意这时函数CreateMutex仍返回真值TRUE),则随后调用的GetLastError函数将返回ERROR_ALREADY_EXISTS,由此得知已有一个应用程序的实例正在运行。

从而弹出消息框提醒用户,然后终止应用程序的当前实例。

在上面的WinMain函数原型中的另一个奇怪的标识符为WINAPI,这是一个在windef.h头文件中定义的宏,在当前版本Win32SDK中,WINAPI被定义为FARPASCAL,因此,使用FARPASCAL同使用WINAPI具有同样的效果,但是,我们强烈建议你使用WINAPI来代替以前常用的FARPASCAL,因为Microsoft不保证FARPASCAL能够在将来的Windows版本中正常工作。

在目前情况下,和FARPASCAL等价的标识符还有CALLBACK(用在如窗口过程或对话框过程之类的回调函数前)和APIENTRY等。

它们对编译器而言都是一回事,最终将被解释为__stdcall。

在Windows环境下编程,会遇到很多这样的情况,注意不要混淆它们。

一般情况下,我们应该在WinMain函数中完成下面的操作:

1.注册窗口类;

2.创建应用程序主窗口;

3.进入应用程序消息循环。

接下来我们将依次讨论这些内容。

在Windows应用程序中,每一个窗口都必须从属于一个窗口类,窗口类定义了窗口所具有的属性,如它的样式、图标、鼠标指针、菜单名称及窗口过程名等。

在注册窗口类前,我们先创建一个类型为WNDCLASS的结构,然后在该结构对象中填入窗口类的信息,最后将它传递给函数RegisterClass,整个过程如下面的代码所示:

WNDCLASSwc;

//填充窗口类信息

wc.style=CS_HREDRAW|CS_VREDRAW;

wc.lpfnWndProc=WndProc;

wc.cbClsExtra=0;

wc.cbWndExtra=0;

wc.hInstance=hInstance;

wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor=LoadCursor(NULL,IDC_ARROW);

wc.hbrBackground=GetStockObject(WHITE_BRUSH);

wc.lpszMenuName=NULL;

wc.lpszClassName="

SdkDemo1"

;

//注册窗口类

RegisterClass(&

wc);

下面解释一下结构WNDCLASS中各成员的含义:

style:

指定窗口样式。

该样式可以为一系列屏蔽位的按位或,在前面的例子中,CS_HREDRAW表示当窗口用户区宽度改变时重绘整个窗口,而CS_VREDRAW则表则表示当窗口用户区高度改变时重绘整个窗口。

对于其它的窗口样式,请参阅SDK中关于WNDCLASS的联机文档。

(顺便说一句,请注意该成员的大小写,它是小写的

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

当前位置:首页 > 求职职场 > 面试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1