• 对话框管理器第四章:对话框消息循环


    对话框消息循环,其实也不复杂,其核心实现代码,也就下面几行代码:

    1. while (<dialog still active> &&
    2. GetMessage(&msg, NULL, 0, 0, 0)) {
    3. if (!IsDialogMessage(hdlg, &msg)) {
    4. TranslateMessage(&msg);
    5. DispatchMessage(&msg);
    6. }
    7. }

    但是,我们还是从头开始讲起吧。故事发生在DialogBoxIndirectParam调用,你应该还记得,我们之前讲解过,系统会将所有对DialogBoxXX的调用,统一转换为对DialogBoxIndirectParam的调用,代码如下:

    1. INT_PTR WINAPI DialogBoxIndirectParam(
    2. HINSTANCE hinst,
    3. LPCDLGTEMPLATE lpTemplate, HWND hwndParent,
    4. DLGPROC lpDlgProc, LPARAM lParam)
    5. {
    6. /*
    7. * App hack! Some people pass GetDesktopWindow()
    8. * as the owner instead of NULL. Fix them so the
    9. * desktop doesn't get disabled!
    10. */
    11. if (hwndParent == GetDesktopWindow())
    12. hwndParent = NULL;

    没错,我们在代码中做了一次App Hack。 在前面的文章中,我们讨论了传递 GetDesktopWindow() 作为父窗口问题。 有很多开发者都犯了这个错误,我们不得不把这个App Hack 内置到核心操作系统代码中。 如果我们不这样做的话,则成百上千的上层应用程序都需要进行改动。

    由于只有顶层窗口可以是窗口所有者,所以我们必须从hwndParent(可能是子窗口)出发,沿着窗口层次结构向上走,直到找到一个顶层窗口。

    1. if (hwndParent)
    2. hwndParent = GetAncestor(hwndParent, GA_ROOT);

    完成了第二次App Hack之后,我们开始创建我们的对话框了:

    1. HWND hdlg = CreateDialogIndirectParam(hinst,
    2. lpTemplate, hwndParent, lpDlgProc,
    3. lParam);

    注意:和以前一样,我将忽略错误检查和各种对话框,因为它只会分散本条目的重点。
    因为模态对话框会禁用它们的父窗口,所以在这里实现它:

     BOOL fWasEnabled = EnableWindow(hwndParent, FALSE);

    然后我们进入对话框模态消息循环:

    1. MSG msg;
    2. while (<dialog still active> &&
    3. GetMessage(&msg, NULL, 0, 0)) {
    4. if (!IsDialogMessage(hdlg, &msg)) {
    5. TranslateMessage(&msg);
    6. DispatchMessage(&msg);
    7. }
    8. }

    根据窗口退出消息的约定,我们重新投递我们可能收到的任何退出消息,以便下一个外部模态循环可以看到它。

    1. if (msg.message == WM_QUIT) {
    2. PostQuitMessage((int)msg.wParam);
    3. }

    (聪明的读者可能已经注意到了看,上面的代码中有一个未初始化的变量错误:如果在 WM_INITDIALOG 处理期间调用了 EndDialog,则永远不会设置 msg.message。出于说明目的,我决定忽略这个错误。)

    至此,我们的对话框完成使命了,我们需要清理一下。 请记住在销毁拥有的对话框之前启用所有者。

    1. if (fWasEnabled)
    2. EnableWindow(hwndParent, TRUE);
    3. DestroyWindow(hdlg);

    最后,返回结果:

    1. return <value passed to EndDialog>;
    2. }

    恭喜,你现在是对话框专家了。 明天,我们将看看,如何充分利用今天学习到的专业知识。

    练习:想办法偷偷穿过两层上面代码中关于父窗口的App Hack,最终得到一个对话框,其所有者是桌面,并解释这种情况的可怕后果。

    总结

    好了,对话框专家,你看到了:代码之下,没有什么神秘的东西,有因就有果。
    这个世界,依然是唯物的。

    最后

    Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
    本文来自:《The dialog manager, part 4: The dialog loop》

  • 相关阅读:
    无损将GPT转换为MBR的GDisk操作指南:
    端口扫描工具是什么?端口扫描工具有什么用
    Linux学习之MySQL建表
    【Jenkins】win 10 / win 11:Jenkins 的下载、安装、部署(Jenkins 2.365 基于 Java 17)
    python监控ES索引数量变化
    『力扣每日一题13』:给定一个整数sum,从有N个有序元素的数组中寻找元素a,b,使得a+b的结果最接近sum,最接近sum,最快的平均时间复杂度是?
    springboot321基于java的校园服务平台设计与开发
    Leetcode算法入门与数组丨5. 数组二分查找
    Three.js 材质的 blending
    SpringMVC实战crud增删改查
  • 原文地址:https://blog.csdn.net/mmxida/article/details/126115249