windows环境下32位汇编语言程序设计(第四章笔记)

第一个窗体程序
 
一、分析窗体程序的结果
入口函数start,然后执行一个_WinMan子程序,完成后就是程序退出的函数ExitaProcess。_WinMain中有几个顺序API函数:
GetModuleHandle------>RtlZeroMemory----->LoadCursor------>RegisterClassEx----->CreateWindowEx--->
ShouWindow------>UpdateWindow
接下来就是3个API组成了循环了:
GetMessage---->TranslateMessage------->DispatchMessage这三个函数组成了消息循环。
 
二、窗体程序的运行过程
1、等到应用程序的句柄(GetModuleHandle)。
2、注册窗体类(RegisterClassEx),填写WNDCLASSEX结构。
3、建立窗口(CreateWindowEx)。
4、显示窗口(ShowWindow)。
5、刷新窗体客户区(UpdateWindows)。
6、进入无限的消息捕获和处理的循环。首先获取消息(GetMessage),如果有消息到达,则将消息分派到回调函数处理(DispatchMessage),如果消息是WM_QUIT,则退出循环。
 
三、模块和句柄
装入内存后运行时就叫模块,每个模块都有一个唯一的模块句柄来标识。
取模块句柄使用的API函数GetModuleHandle,使用方法是:
invoke GetModuleHandle , lpModuleName
lpModuleName是一个指向含有模块名称字符串的指针,NULL得到的是调用者本模块的句柄。如果模块是公用的,每加载“拷贝”一次产生一个实例,每个实例的“实例句柄”不相同。“实例句柄”就是模块句柄。
 
四、创建窗口
1、注册窗口类。首先填写WNDCLASSEX结构,注册窗口类,WNDCLASSEX结构汇编原型:
WNDCLASSEX STRUCT
cbSize  DOWRD ? ; 结构的字节数事实
style     DOWRD ? ; 类风格
lpfnWndProc DOWRD ? ; 窗口过程的地址
cbClsExtra      DOWRD ? ;
cbWndExtra   DOWRD ? ;
hInstance       DOWRD ? ; 所属的实例句柄
hIcon              DOWRD ? ; 窗口图标
hCursor         DOWRD ? ; 窗口光标
hbrBackground DOWRD ? ; 背景色
lpszMenuName DOWRD ? ; 窗口菜单
lpszClassName DOWRD ? ; 类名字符串的地址
hIconSm DOWRD ? ; 小图标
WNDCLASSEX END
使用前用RtlZeroMemory函数对结构体清零。注册后一次性传给RegisterEx函数。
2、建立窗口,窗口的各种风格都是在这里设置的。
invoke CreateWindowEx\
dwExstyle,\;决定窗口外形和行为
lpClassName.\;建立窗口使用的类名字符串指针
lpWindowName,\;指向窗口名称的字符串,标题
dwStyle,\;决定窗口外形和行为
x,\;窗口左上角位置,单位像素。
y,\;窗口左上角位置,单位像素。
nWidth,\;窗口宽度
nHeight,\;窗口高度
hWndParent,\;窗口所属的父窗口,关闭时主要用来销毁子窗口
hMenu,\;窗口上要出现的菜单的句柄
hInstance,\;
lpParam;指向欲传给窗口的参数,在WM_CREATE消息中可以捕获,一般情况用不到这个字段。
建立窗口后eax传回窗口句柄,保存起来备用,ShowWindow函数把它显示出来,显示后用UpdateWindow函数绘制客户区。
五、消息循环
1、消息循环的一般形式
.while TRUE
Invoke GetMessage , addr @stMsg , NULL , 0 , 0
.break .if eax==0
invoke TranslateMessage , addr @stMsg
invoke  DispatchMessage , addr @stMsg
.endw
2、消息循环要用到的结构MSG结构,用来做消息的传递,汇编格式结构体原型:
MSG STRUCT
hwnd DWORD ?;要发向的窗口句柄
message DWORD ?;消息标识,WM_开头,意位windows Message
wParam DWORD ?;消息的参数之一
lParam  DWORD ?;消息参数之二
time  DWORD ?;消息放进消息队伍的时间
pt  DWORD ?;一个POINT数据结构,存放鼠标坐标。
MSG ENDS
这个结构定义了消息的所有属性,GetMessage函数就是从消息队伍列中取出这样的一条消息。
上边的eax==0就是WM_QUIT消息,退出消息循环。
3、TranslateMessage将MSG结构传个windows进行一些键盘消息转换。有键盘按下和放开时,windows产生WM_KEYDOWN和WM_KEYUP或WM_SYSKEYDOWN和WM_SYSKEYUP消息,TranslateMessage函数会键盘的扫描码转成ASCII码,并在队伍中插入WM_CHAR或WM_SYSCHAR消息,只要处理WM_CHAR消息就行了。不是键盘的消息TranslateMessage不处理。
4、最后,由DispatchMessage将消息发送到窗口对应的窗口过程去处理。窗口返回,DispatchMessage返回,开始新一轮循环。
5、其他形式的消息循环。
消息队伍没有消息的时候不让GetMessage在Windows内部等待,把属于自己的CPU时间交出来。
.while TURE
invoke PeekMessage , addr @stMsg , NULL , 0 , 0 ,PM_REMOVE
.if eax
.break .if @stMsg.Message==WM_QUIT
invoke  TranslateMessage , addr @stMsg
invoke  DispatchMessage , addr @stMsg
.else
<其他工作>
.endif
.endw
PeekMessage类似GetMessage,区别于在当队伍有消息的时候,PeekMessage取回消息,并在eax中返回非零值,没有消息的时候eax直接返回0,表示空闲时间。PeekMessage多了一个参数,是否保存队伍中的消息,PM_REMOVE删除,PM_NOREMOVE不删除偷看消息。
六、窗口过程
1、窗口过程是windows回调用的,子程序地址是唯一需要的。窗口过程子程序定义格式:
WindowProc proc hwnd , uMsg , wParam , lParam
窗口过程的一般结构:
WindowProc proc uses ebx edi esi hwnd , uMsg , wParam , lParam;bx edi esi要使用的寄存器
mov eax,uMsg
.if eax==WM_XXX
<处理WM_XXX消息>
.elseif  eax==WM_XXX
<处理WM_XXX消息>
.elseif eax==WM_CLOSE
invoke DestroyWindow , hWinMain;摧毁窗口
invoke  PosQuitMessage , NULL;结束消息循环
.else
invoke  DefWindowProc , hWnd , uMsg , wParam , lParam;系统默认处理
ret;需要返回值就ret保存在eax中
.endif
xor  eax,eax
ret
WindowProc  endp
bx edi esi这几个寄存器要恢复,所有uses引用,自动插入push和pop。
2、接收到的消息顺序
调用CreteWindowEx时窗口过程收到的消息
WM_GETMINMAXINFO 获取窗口大小,以便初始化
WM_NCCREATE 非客户区开始建立
WM_NCCALCSIZE 计算客户区大小
WM_CREATE 窗口建立
调用ShowWindow时窗口过程收到的消息
WM_SHOWWINDOW 显示窗口
WM_WINDOWPOSCHANGING 窗口位置准备改变
WM_ACTIVATEAPP 窗口准备激活
WM_NCACTTVATE 激活状态改变
WM_GETTEXT 取窗口名称,标题
WM_ACTTVATE 窗口准备激活
WM_SETFOCUS 窗口获得焦点
WM_NCPAINT 需要绘画窗口边框
WM_ERASEBKGND 需要擦除背景
WM_WINDOWPOSHANGED窗口位置已经改变
WM_SIZE 窗口大小已经改变
WM_MOVE 窗口位置已经移动
调用UpdateWindow发送一条WM_PAINT消息,接着,主程序进入消息循环,直到DestroyWindow为止。
调用DestroyWindow函数像窗口过程发送的消息:
WM_NCACTVATE 窗口激活状态改变
WM_ACTIVATE 窗口准备非激活
WM_ACTIVATEAPP 窗口准备非激活
WM_KILLFOCUS 失去焦点
WM_DESTROY 窗口即将被摧毁
WM_NCDESTROY 窗口的非客户区以及所有子窗体已经被摧毁
大多数消息是我们不必要关心的,自己不处理的可以交给DefWindowProc 处理,程序关心的消息主要有以下这些:
WM_CREATE 窗口建立
WM_SIZE 窗口大小已经改变
WM_PAINT 如需要自己绘制客户区
WM_CLOSE 确认是否推出就发WM_QUIT消息
WM_DESTROY 窗口摧毁,等扫尾代码
3、消息的默认处理----DefWindowProc
默认预定义消息范围0~03ffh共预定1024个消息编号。
DefWindowProc是一个通用的模块处理消息,ret返回结果就行了。想要不一样的窗口,必须自己定义消息。
唯一注意的是WM_CLOSE消息的时候,自己还要处理WM_DESTROY消息来结束消息循环。
 
七、窗口间的通信
1、 窗口间的消息互发主,窗口间的通信可以用SendMessage或者PostMessage函数,使用格式如下:
invoke  PostMessage , hWnd , Msg , wParam , lParam
invoke  SendMessage , hWnd , Msg , wParam , lParam
对于不同的消息Msg , wParam , lParam参数的含义都不一样。其实就是把消息发给windows,windows再发给要使用的窗口的窗口过程,并返回结果给windows,windows再把结果返回给调用者。
可以接受到不同窗口的字符串,程序地址不同,这是为什么?
因为Windows出来SendMessage消息的时候,检查消息的类型,对不同的类型进行不同的处理,消息是32位数时,就传数值,如果是一个指针的时候,Windows对指向的内容进行了一些处理,以便数据能够正常地传递到目标过程中,其中windows会创建一个共享,窗口过程返回就释放。
注意的是:
在用户自定义消息中(WM_USER等),不要再参数中传递指针,会引发非法访问内存,window只会把lParam和wParam当两个普通的数值传递,不会帮用户把指针的内容复制到一块共享内存中。
2、在窗口间传递数据
Windows提供了特殊的处理消息,WM_COPYDATA。WM_COPYDATA消息用一个COPYDATASTRUCT结构体来描述要拷贝的数据长度和位置:
COPYDATASTRUCT STRUCT
dwData DWORD ?;附加字段,备用字段
cbData  DWORD ?;数据长度,字符数
lpData  DWORD ?;数据位置指针
COPYDATASTRUCT ENDS
3、snedMessage和PostMessage函数的区别
从逻辑上看,SendMessage函数相当于直接调用其他窗口的窗口过程来处理某个消息,并等待窗口过程的返回,在函数返回后,目标窗口过程必定已经处理了该消息。PostMessage函数则将消息放入目标窗口的消息队伍列中并直接返回,函数返回后,目标窗口过程可能还没有处理该消息。
对于普通的消息来说,两个函数没什么两样,但是,对于WM_SETEXT和WM_COPYDATA等在参数中用到指针消息来说,两者就不用了,用PostMessage时,程序根本不会收到WM_SETEXT或者WM_COPYDATA消息,事实上,PostMessage参数中用到指针发送消息都不会成功的。所以,该函数不能用于任何参数中用到指针的消息。
《第四章笔记完,花了我一晚到亮才完成整理,这章内容比较重要所以也比较多,
2012年6月14日8:47完成,QQ:634938543后章节的比较继续中・・・・・・・・・・・・》

你可能感兴趣的:(windows环境下32位汇编语言程序设计(第四章笔记))