windows程序设计第一章讲义.docx

上传人:b****6 文档编号:4279669 上传时间:2022-11-28 格式:DOCX 页数:16 大小:26.84KB
下载 相关 举报
windows程序设计第一章讲义.docx_第1页
第1页 / 共16页
windows程序设计第一章讲义.docx_第2页
第2页 / 共16页
windows程序设计第一章讲义.docx_第3页
第3页 / 共16页
windows程序设计第一章讲义.docx_第4页
第4页 / 共16页
windows程序设计第一章讲义.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

windows程序设计第一章讲义.docx

《windows程序设计第一章讲义.docx》由会员分享,可在线阅读,更多相关《windows程序设计第一章讲义.docx(16页珍藏版)》请在冰豆网上搜索。

windows程序设计第一章讲义.docx

windows程序设计第一章讲义

第一章

这节课我们主要讲解WINDOWS的内部运行原理,要了解VISUALC++程序的开发过程,先要理解WINDOWS应用程序的运行机制,因为VISUALC++是WINDOWS开发语言,我们要明白在WINDOWS环境下编程和在其他环境下一些根本的差别,全面讨论WINDOWS工作原理需要一本书的内容,我们没了解那么细,但还是要了解一些根本的概念原理。

一.Windows应用程序,操作系统,计算机硬件之间的相互关系

Windows程序设计是完全不同于传统的DOS系统的设计方法,它采取事件驱动的机制的程序设计模式,主要是基于消息的。

当用户要实现某种功能时,会调用操作系统的某种支持,然后操作系统将用户的需要包装成消息,并投递到消息队列中,最后应用程序从消息队列中取走消息并进行响应。

向下的箭头①③④表示操作系统能够操作输出设备以执行特定的功能,如让声卡发出声音,显卡画出图形等。

向上的箭头②表示操作系统能够感知输出设备状态的变化,如鼠标移动,键盘按下,并能够知道鼠标移动的位置,键盘按下的哪个键,这就是操作系统和计算机硬件的交互关系。

应用程序开发者通常不需要知道其具体的实现细节,我们关心的是应用程序与操作系统的交互关系。

向下的箭头③表示应用程序可以通知操作系统执行某个具体的动作,如操作系统能够控制声卡发出声音,但它并不知道应该何时发出何种声音,需要应用程序告诉操作系统该发出什么样的声音。

这个关系好比有个机器人能够完成行走的功能,但是,如果人们不告诉它往哪个方向上走,机器人是不会主动行走的。

这里的机器人就是操作系统,人们就是应用程序

那么,应用程序是如何通知操作系统执行某个功能的呢?

有过编程经验的读者都应该知道,在应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。

操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(ApplicationProgrammingInterface),简称WindowsAPI。

如CreateWindow就是一个API函数,应用程序中调用这个函数,操作系统就会按照该函数提供的参数信息产生一个相应的窗口。

在这里注意:

我们不要把API与JAVA或其他的API混淆。

API是一个已经被广泛使用的专业术语,如果说某个系统某个设备提供给应用程序对其进行编程操作的函数,类,组件等的集合。

如做呼叫购买语音卡,提供一个开发包,开发包的函数集合称为语音卡的API。

向上的箭头④表示操作系统能够将输入设备的变化上传给应用程序。

如用户在某个程序活动时按了一下键盘,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件作出反应。

好比有个蚊子叮了我们一口,我们的神经末梢(相当于操作系统)马上感知到这一事件,并传递给了我们的大脑(相当于应用程序),我们的大脑最终决定如何对这一事件作出反应,如将蚊子赶走,或是将蚊子拍死。

对事件作出反应的过程就是消息响应。

2.关于消息及消息队列

操作系统是怎样将感知到的事件传递给应用程序的呢?

这是通过消息机制(Message)来实现的。

操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用程序,参看MSDN。

MSG结构定义如下:

typedefstructtagMSG{

HWNDhwnd;

UINTmessage;

WPARAMwParam;

LPARAMlParam;

DWORDtime;

POINTpt;

}MSG;

解释:

(MSDN是微软提供的程序开发的在线帮助系统,这个系统包括了微软的所有开发语言开发工具的帮助文件,信息很全每年发布4次,一个季度一次。

参数1HWNDhwnd;解释:

handletowindow

新的数据类型,指示窗口的句柄,何谓窗口?

屏幕上的一块矩形区域叫窗口,我们通常的开发的应用程序叫窗口程序,如VISUALC++由许多窗口构成,每个窗口又要起标识,当你去定义一个变量来存储这些标识时,你需要有存储定义这些标识的类型来定义变量,像定义整形变量存放整型数据,定义浮点类型变量存放浮点型数据,要存放窗口标识,需要有窗口句柄来定义这样的变量。

句柄句柄(HANDLE),资源的标识。

操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。

句柄类似指针,也需要占据一块内存,那么对于资源占据一块内存,我们要所引这块内存,索引资源,就是通过句柄找到的。

按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等等各种类型的句柄。

操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。

参数2UINTmessage无符号整型,消息就是具体一个消息,比如,按下鼠标左键,左键作为参数传递过来,整数表示方式。

数值不好记忆,微软定义很多宏,以WM开头,windowmessage,如鼠标左键按下LBUTTONDOWN,键盘按键,KEYDOWN

参数3WPARAMwParam;消息的附加信息

LPARAMlParam;都是整型。

关于消息的附加信息。

如按下A键,WM_CHAR消息,收到消息,我们并不知道那个字母,要想知道,把字母的ASCII码放到附加参数里,这样我们收到消息通过附加参数知道键盘上字母的ASII码。

MSDN查看WM_CHAR消息

既然WPARAMLPARAM都是整型,为什么要再产生两个新的数据类型?

我们看别人写的程序:

intx,y;

x=30;

y=30;

//x和y既可以用来表示坐标点,也可以用来表示宽度和高度,还可以用来表示身高和体重。

typedefintWIDTH

typedefintHEIGHT

WIDTHx;

HEIGHTy;

//好处:

我们从变量的类型上就可以知道x和y是用来表示宽度和高度。

这就是为什么在WINDOWS中微软为我们定义出这么多新的数据类型,虽然都是整型,

参数5DWORD32位整数,指示消息传递出的时间。

参数6POINT点结构体,x,y坐标,当消息被传递时光标在屏幕的位置。

拷贝,查看MSDN

由上看出消息结构体包含很多信息,它包含消息与哪个窗口相关,消息的具体内容是什么,消息的附加参数,消息投递时间和光标位置。

消息队列:

操作系统为每个应用程序都建立一个消息队列,是一个先进先出的缓冲区,通常是某种变量类型的数组,队列中的每个元素都是一个消息,操作系统将生成的每个消息按先后顺序存放到消息队列,应用程序总是取走队列中的第一个消息,消息取走后,第2条成为第1条,后面的依次前提,应用程序取得消息后就知道用户的操作和程序的变化,例如取得WM_CHAR消息,那么一定是用户输入了字符,并且知道是哪个字符。

应用程序得到消息后就要处理消息,这就是消息响应。

消息响应通过编码来实现,这就是WINDOWS程序的主要代码区,需要编写一些编码,这个过程叫消息响应。

在实现过程可以调用API函数,以便完成特定的功能,例如,我们收到关闭窗口的消息,那么可以调用销毁窗口的函数来关闭窗口,或者用弹出消息框的形式询问用户是否真的关闭窗口。

通过以上分析,我们知道要想开发WINDOWS应用程序,除了要具备良好的C++基础,还需要掌握两方面的东西:

一消息本身,知道不同的消息不同的消息代表的用户操作和程序状态本,。

二。

对于不同消息我们要让操作系统执行特定的功能去响应响应

WINMAIN函数

二,Windows程序的结构

1Windows程序的入口函数

intWINAPIWinMain(

HINSTANCEhInstance,//handletocurrentinstance

HINSTANCEhPrevInstance,//handletopreviousinstance

LPSTRlpCmdLine,//commandline

intnCmdShow//showstate

);

查看MSDN

说明:

参数1HINSTANCEhInstance:

应用程序实例句柄,何谓运行程序实例句柄,即运行中的程序,叫实例,再次运行,有两个实例。

这两个实例需要有个标识,同样需要有一种数据类型来定义变量来存放表示,这个类型就是HINSTANCE

参数2HINSTANCEhPrevInstance:

先前实例句柄,对第2个实例,前一个实例就是这个参数。

兄弟实例

注意:

基于w32的应用程序该参数为空如98,NT下开发不需要此参数,为空。

参数3LPSTRlpCmdLine类型是长指针,指向字符串首地址的指针。

命令行参数,

在DOS下MAIN函数可以有两个参数,argv[],argc[],argv[]指针数组,存放命令行参数,argc[]主要接受存放命令行参数个。

同样在WINDOWS程序中也可以接受命令行参数

运行“notepad1.txt”1.txt就是命令行参数

我们的程序中也可以接收命令行参数,project/settings/debug选项卡下programarguments输入“weixin.txt”,在程序中intWINAPIWinMain开始位置设置断点,然后调试运行。

参数4intnCmdShow显示状态,程序运行时是最大化,最小化或隐藏显示。

注意:

WinMain函数是入口点函数,由操作系统调用。

当操作系统启动我们的程序,它会给运行中的程序分配一个实例号,通过参数就传递进来,如果说启动时命令行参数,操作系统会将参数放在第3个参数中,参数都是由操作系统赋值。

2创建一个完整的窗口需要经过下面四个操作步骤:

设计一个窗口类;

注册窗口类;

创建窗口;

显示及更新窗口。

设计窗口WINDOWS已经做好框架,我们只需要填写一部分,如同做填空题一样,这就需要数据结构,结构体

设计一个窗口类;

原因:

程序运行时窗口的样式风格可以不一样,如光标在窗口是箭头还是十字,窗口的标题,背景等等,需要我们在设计窗口时就要确定的

产生一个窗口和设计汽车是一样,生产汽车前,我们都需要在图纸上画出汽车的图,雏形,然后起个名字,比如奔腾600,有了图纸照着生产汽车。

类似产生一个窗口也要设计窗口的特征,没有汽车复杂,windows已经给我们设计了窗口应该有的基本属性,我们要做的就跟做填空题一样,把它填写完整。

(查看MSDN)

typedefstruct_WNDCLASS{

UINTstyle;窗口类的类型,很多。

结合程序看含义-,水平重画和垂直重画,就跟汽车喷漆一样。

WNDPROClpfnWndProc;指针指向窗口过程,也称回调函数

intcbClsExtra;类额外数据,操作系统为系统中每个窗口类管理类结构,当程序注册窗口类,可让系统为追加额外内存空间,我们称为类的附加内存,由属于这种窗口类的所有窗口共享,cbClsExtra,通常为0

intcbWndExtra;操作系统为系统中每个窗口管理类结构,当程序注册窗口,可让系统为追加额外内存空间,我们称为窗口的附加内存

HANDLEhInstance;实例号,设计窗口类,要知道属于哪个

HICONhIcon;图标句柄,通过LoadIcon加载图标

HCURSORhCursor;

HBRUSHhbrBackground;

LPCTSTRlpszMenuName;

LPCTSTRlpszClassName;新类的名字

}WNDCLASS;

UINTstyle

参数1UINTstyle;窗口类的类型,很多。

结合程序看含义-,水平重画和垂直重画,就跟汽车喷漆一样。

在我们的程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。

当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。

当变量中的某几位同时为1时,就表示同时具有几种特性的组合。

一个变量中的哪一位代表哪种意义,不容易记忆,所以我们经常根据特征的英文拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位(bit)为1,其余的bit都为0。

我们使用gotodefinition就能发现CS_VREDRAW=0x0001,CS_HREDRAW=0x0002,CS_DBLCLKS=0x0008,CS_NOCLOSE=0x0200。

他们的共同点就是只有一位为1,其余位都为0。

如果我们希望某一变量的数值既有CS_VREDRAW特性,又有CS_HREDRAW特性,我们只需使用二进制OR(|)操作符将他们进行或运算相组合,如style=CS_VREDRAW|CS_HREDRAW|CS_NOCLOSE。

如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反(~)之后再进行与(&)运算,就能够实现,如在刚才的style的基础上去掉CS_NOCLOSE特征,可以用style&~CS_NOCLOSE实现。

参数2WNDPROClpfnWndProc;指针指向窗口过程,也称回调函数

回调函数的原理是这样的,当应用程序收到给某一窗口的消息时(还记得前面讲过的消息通常与窗口相关的吗?

),就应该调用某一函数来处理这条消息。

这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。

对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?

操作系统调用的就是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。

每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。

举例:

汽车厂家生产汽车好比应用程序创建窗口,用户使用汽车好比操作系统管理窗口,某种汽车在销售前就指定好了修理站(类似回调函数),当用户的汽车出现故障后(类似窗口收到消息),汽车用户(类似操作系统)自己直接找到修理站去修理,不用厂家(类似应用程序)亲自将车送到修理站去修理,但修理站还得由厂家事先建造好。

参数3intcbClsExtra;类额外数据,操作系统为系统中每个窗口类管理类结构,当程序注册窗口类,可让系统为追加额外内存空间,我们称为类的附加内存,由属于这种窗口类的所有窗口共享,cbClsExtra,通常为0,赋为0不是说内存为0,而是我们不需要这个参数。

参数4intcbWndExtra;操作系统为系统中每个窗口管理类结构,当程序注册窗口,可让系统为追加额外内存空间,我们称为窗口的附加内存

参数5HANDLEhInstance;实例号,设计窗口类,要知道属于哪个应用程序实例,因此,当我们对实例赋值时,从winmain中的这个参数,传递过来。

参数6HICONhIcon;图标句柄,通过LoadIcon加载图标,那图标句柄如何赋值?

查看MSDN:

HICONLoadIcon(

HINSTANCEhInstance,//handletoapplicationinstance

LPCTSTRlpIconName//namestringorresourceidentifier

);

当取标准图标时,null。

在windows编程中,当需要某些功能的函数时,可以凭感觉根据语义组合一些名称,如果,createwindow,destroywindow等。

当然符合不符合需要还得去看看含义。

时间长就记住了。

参数7HCURSORhCursor;光标句柄,用LoadCursor与LoadIcon接近,查MSDN

HCURSORLoadCursor(

HINSTANCEhInstance,//handletoapplicationinstance

LPCTSTRlpCursorName//nameorresourceidentifier

);

参数8HBRUSH画刷句柄hbrBackground=GetStockObject()

查MSDN:

HGDIOBJGetStockObject(

intfnObject//stockobjecttype

);

可以修改例子中的参数,改为白色背景。

就跟装修房子刷墙一样,刷什么颜色,墙就是什么颜色。

要有强制类型转换。

参数9LPCTSTRlpszMenuName;指向常量字符串的指针,指向菜单的名字

参数10LPCTSTRlpszClassName;新类的名字,

注册窗口类

设计完窗口类后,要向操作系统注册,RegisterClass(&类名)就如设计完汽车并不能直接生产,要上报进行注册。

查MSDNATOMRegisterClass(

CONSTWNDCLASS*lpWndClass//classdata窗体类结构体的指针

);

创建窗口

首先要定义一个句柄,因为创建窗口和生产汽车一样,生产多少汽车应该有数,同样创建窗口之后,哪个窗口的标识应该保存下来,有哪些窗口。

函数:

CreateWindow(“类名”),查msdn

CreateWindow(//创建具体窗口句柄

参数1LPCTSTRlpClassName//窗口类名,必须与注册时的名字相同,”weixin”,如果换一下,运行后看到,窗口没有产生,但是程序还是运行,从任务管理器可以看到winmain

原因?

参数2LPCTSTRlpWindowNameszTitle,//窗口名字,即标题栏内容

参数3DWORDdwStyle窗口类型即//显示方式,实例中的该参数点右键到gotodefinition

#defineWS_OVERLAPPEDWINDOW(WS_OVERLAPPED|\重叠窗口,有一个标题栏和边框

WS_CAPTION|\有标题栏

WS_SYSMENU|\

WS_THICKFRAME|\创建具有可调边框的

WS_MINIMIZEBOX|\

WS_MAXIMIZEBOX)

这就是以前说的二进制位表示特征,想要某位时置为1,否则置为假,我们可以看看上面这些宏,都是只有1位为1.演示去掉最大化按钮

参数4intx,CW_USEDEFAULT,//初始的X位置

参数5inty,CW_USEDEFAULT,//初始的Y位置

参数6intnWidthCW_USEDEFAULT,/窗口的宽度

参数7intnHeight,//窗口的高度

参数8HWNDNULL,//父窗口句柄,必须与注册时的名字相同

参数9HMENUNULL,//窗口菜单句柄,必须与注册时的名字相同

参数10HINCTANCEhInstance,//实例句柄,必须与程序使用的名字相同

参数11LPVOIDlpParamNULL//窗口创建时作为WMCREATE消息的lpParam附加消息通过结构体传入窗口的数据的指针

当窗口创建好后,就好像汽车造好,要开新闻发布会推出去一样,也需要显示出来。

显示调用函数ShowWindow(hWnd,nCmdShow);

其中第1个参数是窗口句柄,第2个参数是窗口初始显示的形式,nCmdShow参数说明是最大化显示还是最小化显示,应用程序窗口是活动的窗口还是图标,它可置为以“SW_”开始的任何常量,这些常量在windows.h中定义,在WinMain函数中,也是nCmdShow常量决定如何显示主窗口。

在用nCmdShow作为参数调用函数ShowWindow之后,WinMain还要调用UpdateWindow函数。

更新窗口。

不影响窗口更新,可有可无。

3消息循环

MSGmsg;//消息

MSGmsg;

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

{

TranslateMessage(&msg);转化翻译消息,它的作用是对取到的消息对进行转换,什么样的消息对?

当我们在键盘上按下某个按键时,系统会发出WM_KEYDOWN和WM_KEYUP的消息,并且参数中提供的键盘上刚才按键的扫描码,但有时候用户按下的某个键,我们想得到的是表示用户输入的字符的消息,也就是键盘上的某个字母,在消息的补充参数,就是附加参数中提供字母按键的ASCII码。

TranslateMessage能够将WM_KEYDOWN和WM_KEYUP这样的消息对转换为一个WM_CHAR消息,并且将转化后的新消息投递到消息队列中,这个转换过程不会影响原来的消息,只能增加一个消息。

DispatchMessage(&msg);是将我们收到的消息传给回调函数去处理。

我们可以理解为将这个消息路由给操作系统,操作系统去调用窗口过程函数,即回调函数进行处理。

};

}

BOOLGetMessage(

LPMSGlpMsg,//messageinformation,指向消息结构体的指针,out标识表明在传参时不需要给结构体内部数据成员进行初始化,我们只需要定义结构体的变量,将它的地址放在这就可以了。

那么通过函数调用会自动填充消息结构体内部的成员变量。

HWNDhWnd,//handletowindow获取哪个窗口消息,NULL,可以获取所有消息

UINTwMsgFilterMin,//firstmessage消息队列中有很多消息,有的我们感兴趣,有的不,也可以指定消息范围,指定消息最小值。

WM_KEYFIRST指定键盘第一个消息,WM_MOUSEFIRST来指示第一个鼠标消息。

UINTwMsgFilterMax//lastmessage消息最大值,

如果这两个值都设为0,就没有范围过滤了,所有消息都感兴趣。

);

这个消息返回值是BOOL,当取出一个消息时返回真,队列中只要有消息,返回值就是真,就构成循环。

回顾消息循环

我们再看一下窗口过程函数。

MSDN查看WNDCLASS

LRESULTCALLBACKWindowProc(

HWNDhwnd,//handletowindow

UINTuMsg,//messageidentifier

WPARAMwParam,//firstmessageparameter

LPARAMlParam//secondmessageparameter

);

注意:

这是C++程序开发时规定的格式,不能改的,函数名可以变,但是参数类型不能变,名字可以随便取。

LRESULT是LONG型的,长整型。

这4个参数和消息结构体的前4个参数比较类似,实际上是一样的,当DispatchMessage(&msg)执行时,把消息的前4个参数传递过来,消息的后2个参数没有用到,消息投递的时间和坐标在屏幕上的位置。

每当有消息产生时,都要调用窗口过程函数,因此要判断是哪个消息。

RESULTCALLBACKWinSunProc(

HWNDhwnd,//handletowindow

UINTuMsg,

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

当前位置:首页 > 初中教育 > 理化生

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

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