友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
依依小说 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

windows环境下32位汇编语言程序设计-第15部分

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




表4。6  调用CreateWindowEx时窗口过程收到的消息

消息发生
 说    明
 
WM_GETMINMAXINFO
 获取窗口大小,以便初始化
 
WM_NCCREATE
 非客户区开始建立
 
WM_NCCALCSIZE
 计算客户区大小
 
WM_CREATE
 窗口建立
 

表4。7  调用ShowWindow时窗口过程收到的消息

消息发生
 说    明
 
WM_SHOWWINDOW
 显示窗口
 
WM_WINDOWPOSCHANGING
 窗口位置准备改变
 
WM_ACTIVATEAPP
 窗口准备激活
 
WM_NCACTIVATE
 激活状态改变
 
WM_GETTEXT
 取窗口名称(显示标题栏用)
 
WM_ACTIVATE
 窗口准备激活
 
WM_SETFOCUS
 窗口获得焦点
 
WM_NCPAINT
 需要绘画窗口边框
 
WM_ERASEBKGND
 需要擦除背景
 
WM_WINDOWPOSCHANGED
 窗口位置已经改变
 
WM_SIZE
 窗口大小已经改变
 
WM_MOVE
 窗口位置已经移动
 

然后程序执行UpdateWindow,这个函数向窗口过程发送一条WM_PAINT消息,接着,主程序开始进入消息循环,Windows根据各种因素给窗口过程发送相应的消息,一直到调用DestroyWindows为止。表4。8列出了DestoryWindow向窗口过程发送的消息。

表4。8  调用DestroyWindow时窗口过程收到的消息

消息发生
 说    明
 
WM_NCACTIVATE
 窗口激活状态改变
 
WM_ACTIVATE
 窗口准备非激活
 
WM_ACTIVATEAPP
 窗口准备非激活
 
WM_KILLFOCUS
 失去焦点
 
WM_DESTROY
 窗口即将被摧毁
 
WM_NCDESTROY
 窗口的非客户区及所有子窗口已经被摧毁
 

在所有这些阶段的消息中,大部分的消息都不需要程序自己关心,Windows只是尽义务通知窗口过程而已,窗口过程转手就交给DefWindowProc去处理了。程序需要关心的消息有下面这些,可以根据需要选择使用:

●   WM_CREATE——放置窗口初始化代码,如建立各种子窗口(状态栏和工具栏等)。

●   WM_SIZE——放置位置安排的代码,因为建立的子窗口可能需要随窗口大小的改变而移动位置。

●   WM_PAINT——如果需要自己绘制客户区,则在这里安排代码。

●   WM_CLOSE——向用户确认是否退出,如果退出则摧毁窗口并发送WM_QUIT消息。

●   WM_DESTROY——窗口摧毁,在这里放置释放资源等扫尾代码。

在例子程序中,我们处理了WM_PAINT消息来绘制客户区,功能就是在窗口的中间写上一行字:“Win32 Assembly; Simple and powerful !”过程是先通过BeginPaint获取窗口客户区的“设备环境”句柄,然后通过GetClientRect获取客户区的大小,最后通过DrawText函数将字符串按照取得的屏幕大小居中写到“设备环境”中,也就是窗口上。如果不需要显示这个字符串,则连WM_PAINT消息也不用处理。

3。 消息的默认处理——DefWindowProc

Windows预定义的消息范围是0~03ffh,共1 024个消息,查看一下头文件Windows。inc,可以发现实际已定义的消息数目有几百个,这些消息中的大部分对于窗口的运行来说都是必需的,如果窗口过程要处理每一种消息,那么窗口过程中的elseif语句就会绵延数千行,但是窗口的行为就是由处理这些消息的方法来表现的,不处理又不行,怎么办呢?

实际上大部分窗口的行为都是差不多的,这意味着如果要窗口过程处理全部的消息,不同窗口的窗口过程代码应该是大同小异的,那么可以用一个模块来以默认的方式处理消息,Win32中的DefWindowProc函数实现的就是这个功能。

不要小看了这个DefWindowProc,正是它用默认的方式处理了几百种消息,才使用户能用区区百来行代码写出一个全功能的窗口。也正是所有的窗口都用DefWindowProc默认处理程序自己不处理的消息,才使它们的行为看上去大同小异,因为它们背后实际上是同一块代码在处理。

在窗口过程的分支语句中,用户处理所有需要个性化处理的消息,对于表现行为是默认行为的消息,则在else分支中用DefWindowProc来处理,对于Windows来说,它并不关心消息在窗口过程中是程序用自己的代码处理的还是用DefWindowProc处理的,它只看eax中的返回值来了解处理结果,所以不管消息是谁处理的,都必须在eax中返回正确的值。DefWindowProc返回时eax中就是它对消息的处理结果,程序只要直接把eax传回给Windows就行了,所以在例子程序中,DefWindowProc后面直接用一句ret指令返回。

表4。9中列出了DefWindowProc中对一些消息的处理方法,如果和用户期望的不同,就必须在窗口过程中自己处理。

表4。9  DefWindowProc对一些消息的默认处理方式

消    息
 DefWindowProc的处理方式
 
WM_PAINT
 发送WM_ERASEBKGND消息来擦除背景
 
WM_ERASEBKGND
 用窗口类结构中的hbrBackground刷子来绘画窗口背景
 
WM_CLOSE
 调用DestroyWindow来摧毁窗口
 
WM_NCLBUTTONDBLCLK
 这是非客户区(如标题栏)鼠标双击消息,DefWindowProc测试鼠标的位置,然后再采取相应的措施,如标题栏双击将最大化和恢复窗口
 
WM_NCLBUTTONUP
 这是非客户区鼠标释放消息,同样,DefWindowProc测试鼠标的位置然后再采取相应的措施,如鼠标在“关闭”按钮的位置释放将导致发送WM_CLOSE消息
 
WM_NCPAINT
 非客户区绘制消息,DefWindowProc将绘制边框和客户区
 

从这些默认的处理方法可以看出,想要一个窗口和别的窗口看起来不一样,比如想要窗口看起来像苹果机的窗口一样,并且把关闭按钮移到标题栏最左边去,那么可以自己处理WM_NCPAINT消息,把非客户区画成苹果机窗口的样子,并把关闭按钮画到标题栏左边去,并且自己处理WM_NCLBUTTONUP消息,当检测到鼠标按下的位置在自己的关闭按钮上的时候,则发送WM_CLOSE消息。对别的消息的处理思路也可以按这种方法类推。

另外,可以发现DefWindowProc对WM_CLOSE的默认处理是调用DestroyWindow摧毁窗口,DestroyWindow会引发一个WM_DESTROY消息,WM_CLOSE和WM_DESTROY的不同之处是:WM_CLOSE代表用户有关闭的意向,窗口过程有权不“服从”,但收到WM_DESTROY的时候窗口已经在关闭过程中了,不管窗口过程愿不愿意,窗口的关闭已经是不可挽回的事了。

对于这两个消息,窗口过程必须处理其中的一个,因为必须有个地方发送WM_QUIT消息来结束消息循环,例子程序中处理WM_CLOSE消息,在其中用DestoryWindow摧毁窗口,再调用PostQuitMessage结束消息循环;程序也可以不处理WM_CLOSE消息,让DefWindowProc以默认处理的方式摧毁窗口,但这时候必须处理WM_DESTROY消息,在其中调用PostQuitMessage发送WM_QUIT以结束消息循环。




 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第4章 第一个窗口程序


4。3 窗口间的消息互发

    
在前面的内容中,已经知道在不同应用程序之间的窗口中可以互发消息(如图4。4所示),方法是通过SendMessage或者PostMessage函数,它们的用法如下:

    invoke  PostMessage;hWnd;Msg;wParam;lParam

    invoke  SendMessage;hWnd;Msg;wParam;lParam

对于不同的Msg,wParam和lParam的含义是不同的,如对于WM_SETTEXT是:

wParam = 0;                      // 未定义,必须为0

lParam = (LPARAM)(LPCTSTR)lpsz;  // 要设置的字符串地址

想一想就会发现一个问题:Windows中不同应用程序的地址空间是隔离的(如图1。6所示),假设程序1要用SendMessage调用程序2所属窗口的窗口过程,但程序2窗口过程的代码并不在程序1的地址空间中,那么SendMessage如何调用它呢?其实很简单,当程序1调用SendMessage函数的时候,Windows会先保存wParam和lParam参数并等待,等轮到程序2的时间片的时候再去调用它的窗口过程,并把保存的wParam和lParam参数发给它,等窗口过程返回的时候,Windows记下返回值并等待,再等轮到程序1的时间片的时候把返回值当做SendMessage的返回值传给程序1,这样程序1看上去就像自己直接在调用程序2的窗口过程一样。

但又一个问题出现了:Windows在做“牵线红娘”的时候传递了wParam和lParam以及返回值,如果参数指向一个字符串呢,比如说上面的WM_SETTEXT消息中的lParam指向一个字符串,假设程序1中lParam指向字符串的地址为xxxxxxxx,把这个地址传给程序2的时候,程序2不可能访问到程序1的地址空间,在程序2中xxxxxxxx指向的可能是其他内容,也可能是不可访问的,这又该如何处理呢?

写一个源程序实验一下,用一个程序向另一个程序的窗口发送WM_SETTEXT消息,然后在另一个程序中将接收到的WM_SETTEXT消息的参数显示出来。先来打造接收程序,首先拷贝一份FirstWindows的代码,然后在窗口过程的分支中加上以下代码:

。elseif   eax  WM_SETTEXT

          invoke wsprintf;addr szBuffer;addr szReceive;lParam;lParam

          invoke MessageBox;hWnd;offset szBuffer;addr szCaptionMain;MB_OK

同时在数据段中加上下列定义:

szCaptionMain     db       'Receive Message';0

szReceive         db       'Receive WM_SETTEXT message';0dh;0ah

                  db       'param: %08x';0dh;0ah

                  db       'text: 〃%s〃';0dh;0ah;0

在这里,要提及Win32 API中一个很常用的函数wsprintf,这是一个字符串格式化函数,可以将数值按指定格式翻译成字符串,类似于C语言中的printf函数,它的原型是这样的:

int wsprintf(

    LPTSTR lpOut;        // 输出缓冲区地址

    LPCTSTR lpFmt;       // 格式化串地址

    。。。                  // 变量列表

   );

变量列表的数目由格式化字符串规定,wsprintf处理格式化字符串,遇到普通的字符则直接拷贝到输出,遇到%字符则代表有一个变量,%后面不同的字母表示不同的输出格式,如%d表示输出为整数,%x表示输出为16进制,%s表示输出字符串等。

%符号和表示格式的d,x和s等字母间可以用数字来指定输出时占用的位长,这时输出的位长不够时函数会用空格填齐。另外,表示位长的数字前可以加0来表示填齐时用“0”而非空格,如%08x表示输出为8位前面用0填齐的16进制数。wsprintf是Win32 API中惟一一个参数数量不定的函数,使用wsprintf函数的时候,参数的数量取决于格式化字符串中用%号指定的数量,变量列表的数目和格式化串中的%格式一定要一一对应。这里szReceive中有两个%号定义,那么后面就要额外跟两个参数:

    invoke  wsprintf;addr szBuffer;addr szReceive;lParam;lParam

这条语句将lParam的数值以及lParam的字符串按照szReceive格式化串定义的格式转换,并将结果存放到szBuffer中,然后程序将szBuffer中的内容在一个消息框中显示出来:

    invoke  MessageBox;hWnd;offset szBuffer;addr szCaptionMain;MB_OK

接收程序写好了,现在来写一个发送程序,如下所示:

               。386

               。model flat;stdcall

               option casemap:none

;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

include        windows。inc

include        user32。inc

includelib     user32。lib

include        kernel32。inc

includelib     kernel32。lib

;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

               。data

hWnd           dd     ?

szBuffer       db     256 dup (?)

;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

               nst

szCaption      db     'SendMessage';0

szStart        db     'Press OK to start SendMessage; pa
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!