zoukankan      html  css  js  c++  java
  • 窗口过程

    窗口过程是给 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 无法确定哪个窗口关闭代表着整个程序的结束,所以。。。。。。

  • 相关阅读:
    解决clipboard.js在移动端复制失败的问题
    在HTML中使用JavaScript(浏览器对js的加载机制分析)
    前端mv框架下(目前写的是vue),对组件抽象的思考
    github在不同电脑上协同开发
    日语五十音图快速记忆法——看了这个,真的很好记
    Day2 CSE101 L2
    PRISM概率模型检测器初使用骰子模型
    PRISM概率模型检测器初使用(2)嵌入式控制系统模型
    Day1 CSE101 L1
    prism model check 的环境安装设置
  • 原文地址:https://www.cnblogs.com/poli/p/4856847.html
Copyright © 2011-2022 走看看