窗口过程

窗口过程是给 Windows 回调用的,它必须遵循规定的格式。

对窗口过程的子程序名并没有规定,对Windows来说,窗口过程的地址才是惟一需要的,例子程序中的子程序名是 _ProcWinMain,鱼油们可以改用其他任何你喜欢的名称。

窗口过程子程序的参数格式为:
WindowProc  proc hwnd, uMsg, wParam, lParam

第一个参数是窗口句柄,因为一个窗口过程可能为多个基于同一个窗口类的窗口服务。
Windows 回调的时候必须指出要操作的具体窗口,否则窗口过程不知道要去处理哪个窗口。
我们的 FirstWindow 程序只建立了一个窗口,所以每次传递过来的 hwnd 和用 CreateWindowEx 函数返回的窗口句柄是一样的
第二个参数是消息标识,后面两个参数是消息的两个参数。(这4个参数和消息循环中MSG结构中的前4个字段是一样的)

窗口过程的结构流程

WindowProc proc uses ebx edi esi, hWnd, uMsg, wParam, lParam
mov eax, uMsg
.if eax == WM_XXX
<处理WM_XXX消息>
.elseif eax == WM_YYY
<处理WM_YYY消息>
.elseif eax == WM_CLOSE
invoke DestroyWindow, hWinMain
invoke PostQuitMessage, NULL
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
xor eax,eax
ret
WindowProc endp

该过程主要是对 uMsg 参数中的消息编号构成一个分支结构,对于需要处理的消息分别处理。
不感兴趣的消息则交给 DefWindowProc 处理。
要注意的是窗口过程中要注意保存 ebx,edi,esi 和 ebp 寄存器。( uses ebx edi esi )
高级程序中不用自己操心这一点,但是在我们汇编中就要注意了,Windows内部将这4个寄存器当指针使用,如果返回时如果在程序中改变了它们的值,程序会马上崩溃。

proc 后面的 uses 伪操作作用是在子程序进入和退出时自动安插上 push 和 pop 来保护这些寄存器的值。
其实不仅是在窗口过程中是这样,所有由应用程序提供给 Windows 的回调函数都必须遵循这个规定,如很快我们会谈到的定时器回调函数等。
所有Win32 API也遵循这个规定,所以调用API后,ebx,edi,esi 和 ebp 寄存器的值总是不会被改变的,但 ecx 和 edx 的值就不一定了。

uMsg 参数指定的消息有一定的范围,Windows标准窗口中已经预定义的值在 0~03ffh 之间,
我们可以自定义一些消息,通过 SendMessage 等函数传给窗口过程做自定义的处理工作,这时可以使用的值是从 0400h 开始的。
wParam 和 lParam 参数是消息所附带的参数,它随消息的不同而不同,对于不同的消息,它们的含义必须分别从手册中查明:如 WM_MOUSEMOVE 消息中,wParam 是标志,lParam 是鼠标位置;而在 WM_GETTEXT 消息中,wParam 是要获取的字符数,lParam 是缓冲区地址。。。。。。

处理了不同的消息,必须返回规定的值给Windows,返回值也可以分别从手册中查明。

比如处理 WM_CREATE 消息的时候,如果返回 0 表示成功;如果程序无法初始化,如申请内存失败,那么可以返回-1,Windows 就不会继续窗口的创建过程。

一些消息的返回值则没有定义,但大部分的消息处理以后都以返回 0 表示成功,程序中把默认的返回语句放在最后,将 eax 清零后返回。(xor eax, eax)

在处理某个消息的时候需要返回不同的值,可以在分支中将 eax 赋值后直接用 ret 指令返回。
然而对于 DefWindowProc 的返回值,我们不对它进行干涉,所以直接将 eax 不做修改地用 ret 返回。
WM_CLOSE 消息是按下了窗口右上角的 ”关闭” 按钮后收到的,程序可以在这里处理和关闭窗口相关的事情,一般是相关资源的释放工作,如释放内存、保存工作和提示用户是否保存工作等。

例如记事本程序在未保存的时候单击 “关闭” 按钮,会有提示框提示是否先保存文件,单击 “取消”按钮的话,记事本不会关闭,这个步骤就是在 WM_CLOSE 消息处理中完成的。

如果处理 WM_CLOSE 消息时直接返回,那么窗口不会关闭,因为这个消息只是 Windows 通知窗口用户单击了 ”关闭” 按钮而已,窗口采取什么样的行为是窗口的事。
CloseMe

而一般的情况下,当窗口决定关闭的时候,需要程序自己调用 DestroyWindow 来摧毁窗口,并用 PostQuitMessage 向消息循环发送WM_QUIT消息来退出消息循环。
调用 PostQuitMessage 时的参数是退出码,就是 GetMessage 收到 WM_QUIT 后 MSG 结构 wParam 字段中的东西,在这里使用 NULL 即可。
PostQuitMessage 是初学者容易遗漏的函数,如果没有这条语句,外观上窗口是被摧毁掉,从屏幕上消失了,但主程序中的消息循环却没有收到 WM_QUIT,结果还在那里打转。

常有人调试的时候丢了这条语句,结果再一次编译的时候就收到错误:LINK fatal error LNK1104: cannot open file “xxx.exe” 表示exe文件不可写!

那么 Windows 为什么不在窗口摧毁的时候自动发送一个 WM_QUIT 消息,而必须由用户程序自己通过 PostQuitMessage 函数发送呢?
其实很好理解:因为一个程序可能不止一个窗口,Windows 无法确定哪个窗口关闭代表着整个程序的结束,所以。。。。。。

原文地址:https://www.cnblogs.com/poli/p/4856847.html