模态对话框中错误的父 HWND

Wrong parent HWND in modal dialog

为什么我在此处将桌面作为我的模式对话框的父 HWND?

class CSaveProfileAsDlg:
 public CSimpleDialog<IDD_DLG_RESOURCE>
{
  ....
  LRESULT OnInitDialog(UINT,  WPARAM, LPARAM, BOOL&)
  {
    ...
    HWND parent = GetParent(); // or GetAncestor(m_hWnd, GA_PARENT);
    assert(parent != GetDesktopWindow()); // not ok
    ...
  }
 ....
}


//somewhere in code
//m_hWnd is some valid HWND
assert(m_hWnd != GetDesktopWindow()); //ok
CSaveProfileAsDlg dlg;
dlg.DoModal(m_hWnd /*as a parent wnd*/);

我可以通过在 CSaveProfileAsDlg ctor 中传递正确的 HWND 来 "solve" 它,但我想要正确的解决方案。

谢谢!

文档非常混乱,但我想我找到了问题所在。 DoModal 内部调用 ::DialogBox(),其中一个参数采用名为 hWndParentHWND。来自 documentation:

hWndParent [in, optional]
Type: HWND
A handle to the window that owns the dialog box.

这里的关键词是"owns"这个词。关于 owned windows 的部分证实了这一点:

Dialog boxes and message boxes are owned windows by default. An application specifies the owner window when calling a function that creates a dialog box or message box.

所以我们实际上谈论的是所有者 window 而不是它的 parent。这是有道理的,因为对话框是自由浮动的 window,而不是 "parenthood" 所暗示的 window 层次结构的一部分。

您可以通过以下方式获得所有权 window:

HWND parent = ::GetWindow(m_hWnd, GW_OWNER);

我遇到了类似的问题。我想知道为什么 GetParent() return 总是不同的 CWnd*.

正确的解决方案很简单,只需将所需的 pWnd 传递给 dlg 构造函数即可。
会保存在CDialog成员变量m_pParentWnd.
中 然后你总是可以在你的Dialog中用这个成员变量获取传递的pWnd。

//somewhere in code
//pWnd some valid CWnd pointer

CSaveProfileAsDlg dlg (pWnd);  // relevant!
dlg.DoModal();

.

class CSaveProfileAsDlg:
 public CSimpleDialog<IDD_DLG_RESOURCE>
{
  ....
  LRESULT OnInitDialog(UINT,  WPARAM, LPARAM, BOOL&)
  {
    ...
    CWnd* _pWnd = GetParent();  // not ok, returns probably CMainFrame or similiar
    CWnd* pWnd = m_pParentWnd;  // your parent Wnd
    ...
  }
 ....
}

我有同一个应用程序的两个版本,其中一个禁用所有父弹出窗口 windows,就像调用 DoModal 时应该的那样。第二个版本仅禁用顶级 CMainFrame 并且真正的父级保持启用状态,因此我可以调用模态对话框两次或更多次。

这发生在 CWnd::GetSafeOwner_ 行: hWnd = ::GetLastActivePopup(hWnd);

第一个版本 return 真正的父级,而第二个版本 return CMainFrame。 我花了一天时间,找不到这种行为的原因。但是我找到了解决方法:

调用 DoModal 时禁用 CMainFrame,这样我也可以禁用它的子项:

afx_msg void OnEnable(BOOL bEnable);

ON_WM_ENABLE()

void CMainFrame::OnEnable(BOOL bEnable)
{
    std::for_each(m_bars.begin(), m_bars.end(), 
        [=](const std::pair<EBar, BaseBar*>& bar)
    { 
        bar.second->EnableWindow(bEnable);
    });
}