PostMessage() 成功,但我的消息处理代码从未收到消息

发布于 2024-11-17 09:22:48 字数 2138 浏览 3 评论 0原文

在我的 C++ 应用程序的 GUI 对象中,主窗口过程中有以下内容:

case WM_SIZE:
    {
        OutputDebugString(L"WM_SIZE received.\n");
        RECT rect = {0};
        GetWindowRect(hwnd, &rect);
        if (!PostMessage(0, GUI_MSG_SIZECHANGED, w, MAKELONG(rect.bottom - rect.top, rect.right - rect.left))) {
            OutputDebugString(L"PostMessage failed.\n"); // <--- never called
        }
    }

    return 0; // break;

GUI 对象还具有以下 getMessage() 方法:

int GUI::getMessage(MSG & msg) {
    BOOL result = 0;

    while ((result = GetMessage(&msg, 0, 0, 0)) > 0) {
        if (msg.message > (GUI_MSG_BASE-1) && msg.message < (GUI_MSG_LAST+1)) {
            OutputDebugString(L"GUI message received.\n");
            break;
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return result;
}

应用程序对象按以下方式调用此方法:

while ((result = _gui.getMessage(msg)) > 0) {
    switch (msg.message) {
        // TODO: Add gui message handlers
        case GUI_MSG_SIZECHANGED:
            OutputDebugString(L"GUI_MSG_SIZECHANGED received.\n");
            _cfg.setWndWidth(HIWORD(msg.lParam));
            _cfg.setWndHeight(LOWORD(msg.lParam));
            if (msg.wParam == SIZE_MAXIMIZED)
                _cfg.setWndShow(SW_MAXIMIZE);
            else if (msg.wParam == SIZE_MINIMIZED)
                _cfg.setWndShow(SW_MINIMIZE);
            else if (msg.wParam == SIZE_RESTORED)
                _cfg.setWndShow(SW_SHOWNORMAL);
            break;
    }
}

应用程序对象对窗口大小感兴趣,因为它将此信息存储在配置文件中。

当我在 Visual Studio 的调试器中运行此命令时,调整窗口大小后的输出窗口如下所示:

WM_SIZE received.
GUI message received.
GUI_MSG_SIZECHANGED received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
...etc...

PostMessage() 函数永远不会失败,但似乎只在第一次处理 WM_SIZE 时发送 GUI_MSG_SIZECHANGED (#define as WM_APP + 0x000d),这就在处理 WM_CREATE 之后。

我不知道是什么原因造成的。我尝试使用 SendMessage 和 PostThreadMessage 但结果是相同的。还通读了 MSDN 的消息处理文档,但找不到我的代码有什么问题。

有人可以帮忙吗?

In my C++ application's GUI object I have the following in the main window procedure:

case WM_SIZE:
    {
        OutputDebugString(L"WM_SIZE received.\n");
        RECT rect = {0};
        GetWindowRect(hwnd, &rect);
        if (!PostMessage(0, GUI_MSG_SIZECHANGED, w, MAKELONG(rect.bottom - rect.top, rect.right - rect.left))) {
            OutputDebugString(L"PostMessage failed.\n"); // <--- never called
        }
    }

    return 0; // break;

The GUI object also has the following getMessage() method:

int GUI::getMessage(MSG & msg) {
    BOOL result = 0;

    while ((result = GetMessage(&msg, 0, 0, 0)) > 0) {
        if (msg.message > (GUI_MSG_BASE-1) && msg.message < (GUI_MSG_LAST+1)) {
            OutputDebugString(L"GUI message received.\n");
            break;
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return result;
}

The application object calls this method in the following way:

while ((result = _gui.getMessage(msg)) > 0) {
    switch (msg.message) {
        // TODO: Add gui message handlers
        case GUI_MSG_SIZECHANGED:
            OutputDebugString(L"GUI_MSG_SIZECHANGED received.\n");
            _cfg.setWndWidth(HIWORD(msg.lParam));
            _cfg.setWndHeight(LOWORD(msg.lParam));
            if (msg.wParam == SIZE_MAXIMIZED)
                _cfg.setWndShow(SW_MAXIMIZE);
            else if (msg.wParam == SIZE_MINIMIZED)
                _cfg.setWndShow(SW_MINIMIZE);
            else if (msg.wParam == SIZE_RESTORED)
                _cfg.setWndShow(SW_SHOWNORMAL);
            break;
    }
}

The application object is interested in the window size because it stores this information in a configuration file.

When I run this in Visual Studio's debugger, the output window looks like this after resizing the window:

WM_SIZE received.
GUI message received.
GUI_MSG_SIZECHANGED received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
...etc...

The PostMessage() function never fails, but seems to only send GUI_MSG_SIZECHANGED (#defined as WM_APP + 0x000d) the first time WM_SIZE is handled, which is right after handling WM_CREATE.

I have no idea what could be causing this. I tried using SendMessage and PostThreadMessage but the result is the same. Also read through MSDN's message handling documentation but couldn't find what's wrong with my code.

Could anyone help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

刘备忘录 2024-11-24 09:22:48

破解自定义消息循环是你有一天会后悔的事情。你打得很早。

不要使用 NULL 窗口句柄发布消息,只有当您可以保证您的程序仅泵送您的自定义消息循环时,它们才能工作。你不能做出这样的保证。一旦您启动对话框或 Windows 决定自行泵送消息循环,这些消息就会落入位桶中。当用户调整窗口大小时就是这种情况,调整大小逻辑是模态的。 Windows 泵有自己的消息循环,WM_ENTERSIZEMOVE 宣布它。这也是如果线程能够显示任何窗口,PostThreadMessage 就是邪恶的原因。即使是 MessageBox 也是致命的。 DispatchMessage 无法传递消息。

创建一个充当控制器的隐藏窗口。现在您可以在其窗口过程中检测到 GUI_MSG_SIZECHANGED,并且无需对消息循环进行修改。顺便说一句,该控制器通常是应用程序的主窗口。

Hacking a custom message loop is something you'll live to regret some day. You hit it early.

Don't post messages with a NULL window handle, they can only work if you can guarantee that your program only ever pumps your custom message loop. You cannot make such a guarantee. These messages fall into the bit bucket as soon as you start a dialog or Windows decides to pump a message loop itself. Which is the case when the user resizes a window, the resize logic is modal. Windows pumps its own message loop, WM_ENTERSIZEMOVE announces it. This is also the reason that PostThreadMessage is evil if the thread is capable of displaying any window. Even a MessageBox is fatal. DispatchMessage cannot deliver the message.

Create a hidden window that acts as the controller. Now you can detect GUI_MSG_SIZECHANGED in its window procedure and no hacks to the message loop are necessary. That controller is not infrequently the main window of your app btw.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文