结束自定义对话框的嵌套消息循环

我在内存中有一个由对话框模板制成的对话框类,它运行它自己的嵌套消息循环(除了主应用程序msg循环外)。

要创建对话框,请使用CreateDialogIndirectParamW,它将句柄返回到对话框窗口

由于对话框是完全自定义的,因此所有消息处理和创建都是手动完成的。

我省略了Dialog过程,但是基本上,一旦对话框关闭,它将调用以下相关的消息处理程序。

请注意,我们不能使用EndDialog函数破坏对话框并结束消息循环,因为对于CreateDialogIndirectParamW,我们必须显式使用DestroyWindow

我正在寻找结束对话循环的有效方法。

我尝试实现this loop,但是问题在于这种方法会消耗过多的CPU资源,因为示例代码中的for循环只会愚蠢地运行直到出现消息为止,或者如果{忽略{1}},然后for将立即停止循环,这不是我想要的。

相关的类声明:

PeekMessage

简化的类定义:

class Dialog :
    public ContainerWindow,public MessageWindow,public SuperClassWindow
{
    // ...

public:
    /** Process messages for dialog window */
    [[nodiscard]] int RunmessageLoop() override;

protected:
    /** Handler for WM_NCDESTROY */
    std::uint32_t OnNcDestroy(const UINT& uMsg,const WPARAM& wParam,const LPARAM& lParam) override;

    /** Handler for WM_DESTROY */
    inline void OnDestroy() const noexcept override;

    /** Handler for WM_CLOSE */
    inline virtual bool OnClose() noexcept;

    // ...

protected:
        HWND mhWnd;                 /** Window handle of derived component */
    }

这是对话框的消息循环: 我需要在循环中添加一些检查代码以检查对话框是否有效,也就是说,如果已删除对话框对象,则以某种方式停止循环

一旦调用std::uint32_t Dialog::OnNcDestroy( [[maybe_unused]] const UINT& uMsg,[[maybe_unused]] const WPARAM& wParam,[[maybe_unused]] const LPARAM& lParam) { // ... delete this; // note we can't set this pointer to nullptr! // ... return count; } void Dialog::OnDestroy() const noexcept { PostQuitMessage(0); } bool Dialog::OnClose() noexcept { return DestroyWindow(mhWnd); } 处理程序,下面的OnNcDestroy将失败,请参见注释。

看起来IsDialogMessageW将在分派GetMessageW之后继续运行,该循环仍在等待WM_NCDESTROY处理程序发送的WM_QUIT,因此,一旦对话框对象被删除,这将使OnDestroy失败。因为IsDialogMessageW(mhWnd,&msg)不再存在。

mhWnd

请注意,我们不能int Dialog::RunmessageLoop() { EnableWindow(mhWndParent,FALSE); MSG msg{ }; BOOL result = FALSE; while ((result = GetMessageW(&msg,nullptr,0)) != FALSE) { if (result == -1) { ShowError(ERR_BOILER); // error checking function. break; } // once OnNcDestroy is called "mhWnd" is invalid memory // and this will off course cause access violation! if (!IsDialogMessageW(mhWnd,&msg)) { TranslateMessage(&msg); DispatchMessageW(&msg); } } EnableWindow(mhWndParent,TRUE); return static_cast<int>(msg.wParam); } ,因为if (this)不是this,并且不能在nullptr处理程序中设置为nullptr

qjjjjwqvcrrxx 回答:结束自定义对话框的嵌套消息循环

好的,经过一段时间的试验,我对代码进行了以下更改,使所有功能均正常运行! (请参阅评论以获取更多信息)

顺便说一句。我将保留这个问题,希望有一种更有效的方法,目前每条消息都调用IsWindow,这可能是性能问题。

int Dialog::RunMessageLoop()
{
    EnableWindow(mhWndParent,FALSE);

    MSG msg{ };
    BOOL result = FALSE;

    // first we save the handle to the window
    HWND hwnd = mhWnd;
    if (!IsWindow(hwnd)) // make sure the handle is valid dialog window
        std::abort();

    while ((result = GetMessageW(&msg,nullptr,0)) != FALSE)
    {
        if (result == -1)
        {
            ShowError(ERR_BOILER);
            break;
        }

        // if object is deleted the handle is no longer valid!
        // because prior to OnNcDestroy handler DestroyWindow has been called
        if (!IsWindow(hwnd))
            goto invalid;

        if (!IsDialogMessageW(mhWnd,&msg))
        {
        invalid: // non dialog message processing
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    // NOTE that we removed EnableWindow(mHwndParent) here!

    return static_cast<int>(msg.wParam);
}

这可以单独使用,但是另一个步骤是在销毁对话框之前启用所有者窗口(主窗口),因此更新处理程序:

bool Dialog::OnClose() noexcept
{
    // otherwise first window in Z order (such as Desktop) will get focus!
    EnableWindow(mhWndParent,TRUE); 

    return DestroyWindow(mhWnd);
}
本文链接:https://www.f2er.com/3167340.html

大家都在问