友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
读书室 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

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

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


                                   addr @stRect;

                                   DT_SINGLELINE or DT_CENTER or DT_VCENTER

 

                          invoke    EndPaint;hWnd;addr @stPs

;********************************************************************

                 。elseif  eax     WM_CLOSE

                          invoke    DestroyWindow;hWinMain

                          invoke    PostQuitMessage;NULL

;********************************************************************

                 。else

                          invoke    DefWindowProc;hWnd;uMsg;wParam;lParam

                                   ret

                          。endif

;********************************************************************

                 xor      eax;eax

                 ret

 

_ProcWinMain     endp

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

_WinMain         proc

                 local    @stWndClass:WNDCLASSEX

                 local    @stMsg:MSG

 

                 invoke   GetModuleHandle;NULL

                 mov                hInstance;eax

                 invoke   RtlZeroMemory;addr @stWndClass;sizeof @stWndClass

;********************************************************************

; 注册窗口类

;********************************************************************

                 invoke   LoadCursor;0;IDC_ARROW

                 mov      @stWndClass。hCursor;eax

                 push     hInstance

                 pop      @stWndClass。hInstance

                 mov      @stWndClass。cbSize;sizeof WNDCLASSEX

                 mov      @stWndClass。style;CS_HREDRAW or CS_VREDRAW

                 mov      @stWndClass。lpfnWndProc;offset _ProcWinMain

                 mov      @stWndClass。hbrBackground;COLOR_WINDOW + 1

                 mov      @stWndClass。lpszClassName;offset szClassName

                 invoke   RegisterClassEx;addr @stWndClass

;********************************************************************

; 建立并显示窗口

;********************************************************************

                 invoke   CreateWindowEx;WS_EX_CLIENTEDGE;

                          offset szClassName;offset szCaptionMain;

                          WS_OVERLAPPEDWINDOW;

                          100;100;600;400;

                          NULL;NULL;hInstance;NULL

                 mov      hWinMain;eax

                 invoke   ShowWindow;hWinMain;SW_SHOWNORMAL

                 invoke   UpdateWindow;hWinMain

;********************************************************************

; 消息循环

;********************************************************************

                 。while   TRUE

                          invoke    GetMessage;addr @stMsg;NULL;0;0

                          。break    。if eax   0

                          invoke    TranslateMessage;addr @stMsg

                          invoke    DispatchMessage;addr @stMsg

                 。endw

                 ret

 

_WinMain         endp

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

start:

                 call     _WinMain

                 invoke   ExitProcess;NULL

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

                 end      start



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


第4章 第一个窗口程序


4。1 开始了解窗口(3)

    
让我们打开一个DOS窗口,切换到FistWindow所在的目录,运行环境设置的批处理文件var。bat,再键入nmake编译出FirstWindow。exe,这个程序只有2 560字节,运行后窗口出来了,如图4。3所示。对于这个窗口,用户可以拖动边框去改变大小、按标题栏上的按钮来最大化和最小化,当光标移到边框的时候,会自动变成双箭头……总之,这个窗口包括了一个典型窗口的所有特征。


图4。3  FirstWindow的运行结果

接下来开始分析源代码,看了这三页多的源代码,第一个感觉是什么?是不是想撤退了?笔者刚开始编Win32程序的时候就是这种感觉,可能90%的人有同样的感觉,别急,过了这一关,Win32汇编的入门就成功了一半,所以千万要挺住!有个振奋人心的消息是,这个程序是大部分窗口程序的模板,以后要写一个新的程序,把它拷贝过来再往中间添砖加瓦就是了,功夫一点都不白费。

先静下心来分析一下程序的结构,还看得懂,很好!其实源程序的结构在第3章里已经了解过了,首先是注释……模式定义……include…… 。data数据段,都没有问题,这些已经占去了近40行了,好了,终于是关键的代码段了,统计一下,只剩80行代码了。

分析一下程序的结构,发现入口是start,然后执行了一个_WinMain子程序,完成后就是程序退出的函数ExitProcess,再看_WinMain的结构,前面是顺序下来的几个API:

GetModuleHandle → RtlZeroMemory → LoadCursor  → RegisterClassEx

→ CreateWindowEx → ShowWindow → UpdateWindow

从名称上就能看出它们的用途,很明显,窗口是在CreateWindowEx处建立的,ShowWindow则是把窗口显示在屏幕上,这些代码是窗口的建立过程。

接下来,就是一个由3个API组成的循环了:

GetMessage → TranslateMessage → DispatchMessage

很明显,这是和消息有关的循环,因为API名称中都带有Message字样,如果退出这个循环,程序也就结束了,这个循环叫做消息循环。设置_WinMain子程序并不是必须的,可以把_WinMain的所有代码放到主程序中,没有任何影响,之所以这样只是为了将这里使用的变量定义成局部变量,这样可以方便移植。

看了程序的流程,似乎没有什么地方涉及窗口的行为,如改变大小和移动位置的处理等。再看源程序,除了_WinMain,还有一个子程序_ProcWinMain,但除了在WNDCLASSEX结构的赋值中提到过它,好像就没有什么地方要用到这个子程序,起码在自己编写的源代码中没有任何一个地方调用过它。

再看_ProcWinMain,它是一个分支结构处理的子程序,功能是把参数uMsg取出来,根据不同的uMsg执行不同的代码,完了以后就退出了,中间也没有任何东西和主程序有关联。

第一个窗口程序就是由这么两个似乎是风马牛不相及的部分组成的,但它确实能工作,对于写惯了DOS汇编的程序员来说,这似乎不可理解。下面来看看这么一个陌生而奇怪的程序是如何工作的。

3。 窗口程序的运行过程

在屏幕上显示一个窗口的过程一般有以下步骤,这就是主程序的结构流程:

(1)得到应用程序的句柄(GetModuleHandle)。

(2)注册窗口类(RegisterClassEx)。在注册之前,要先填写RegisterClassEx的参数WNDCLASSEX结构。

(3)建立窗口(CreateWindowEx)。

(4)显示窗口(ShowWindows)。

(5)刷新窗口客户区(UpdateWindow)。

(6)进入无限的消息获取和处理的循环。首先获取消息(GetMessage),如果有消息到达,则将消息分派到回调函数处理(DispatchMessage),如果消息是WM_QUIT,则退出循环。

程序的另一半_ProcWinMain子程序是用来处理消息的,它就是窗口的回调函数(Callback),也叫做窗口过程,之所以是回调函数是因为它是由Windows而不是我们自己调用的,我们调用DispatchMessage,而DispatchMessage再回过来调用窗口过程。

所有的用户操作都是通过消息来传给应用程序的,如用户按键,鼠标移动,选择了菜单和拖动了窗口等,应用程序中由窗口过程接收消息并处理,在例子程序中就是_ProcWinMain。窗口过程构造了一个分支结构,对应不同的消息执行不同的代码,所以一个应用程序中几乎所有的功能代码都集中在窗口过程里。

窗口程序运行中消息传输的流程可以由图4。4来表示。

先来看看Windows对消息的处理。Windows在系统内部有一个系统消息队列,当输入设备有所动作的时候,如用户按动了键盘、移动了鼠标,按下或放开了鼠标等,Windows都会产生相应的记录放在系统消息队列里,如图4。4中的箭头a和b所示,每个记录中包含消息的类型、发生的位置(如鼠标在什么坐标移动)和发生的时间等信息。


图4。4  窗口程序的运行过程

同时,Windows为每个程序(严格地说是每个线程)维护一个消息队列,Windows检查系统消息队列里消息的发生位置,当位置位于某个应用程序的窗口范围内的时候,就把这个消息派送到应用程序的消息队列里,如图4。4中的箭头c所示。

当应用程序还没有来取消息的时候,消息就暂时保留在消息队列里,当程序中的消息循环执行到GetMessage的时候,控制权转移到GetMessage所在的USER32。DLL中(箭头1),USER32。DLL从程序消息队列中取出一条消息(箭头2),然后把这条消息返回应用程序(箭头3)。

应用程序可以对这条消息进行预处理,如可以用TranslateMessage把基于键盘扫描码的按键消息转换成基于ASCII码的键盘消息,以后也会用到TranslateAccelerator把键盘快捷键转换成命令消息,但这个步骤不是必需的。

然后应用程序将处理这条消息,但方法不是自己直接调用窗口过程来完成,而是通过DispatchMessage间接调用窗口过程,Dispatch的英文含义是“分派”,之所以是“分派”,是因为一个程序可能建有不止一个窗口,不同的窗口消息必须分派给相应的窗口过程。当控制权转移到USER32。DLL中的DispatchMessage时,DispatchMessage找出消息对应窗口的窗口过程,然后把消息的具体信息当做参数来调用它(箭头5),窗口过程根据消息找到对应的分支去处理,然后返回(箭头6),这时控制权回到DispatchMessage,最后DispatchMessage函数返回应用程序(箭头7)。这样,一个循环就结束了,程序又开始新一轮的GetMessage。

有个很常见的问题:为什么要由Windows来调用窗口过程,程序取了消息以后自己处理不是更简便吗?事实上并非如此,如果程序自己处理消息的“分派”,就必须自己维护本程序所属窗口的列表,当程序建立的窗口不止一个的时候,这个工作就变得复杂起来;另一个原因是:别的程序也可能用SendMessage通过Windows直接调用你的窗口过程;第三个原因:Windows并不是把所有的消息都放进消息队列,有的消息是直接调用窗口过程处理的,如WM_SETCURSOR等实时性很强的消息,所以窗口过程必须开放给Windows。

应用程序之间也可以互发消息,PostMessage是把一个消息放到其他程序的消息队列中,如图4。4中箭头d所示,目标程序收到了这条消息就把它放入该程序的消息队列去处理;而SendMessage则越过消息队列直接调用目标程序的窗口过程(如图4。4中箭头I所示),窗口过程返回以后才从SendMessage返回(如图4。4中箭头II所示)。

窗口过程是由Wind
返回目录 上一页 下一页 回到顶部 1 4
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!