fogbit
fogbit

Reputation: 2063

Wrong parent HWND in modal dialog

Why do i get desktop as a parent HWND for my modal dialog here?

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*/);

I can "solve" it by passing corret HWND in CSaveProfileAsDlg ctor, but i'd like to have correct solution.

Thank you!

Upvotes: 1

Views: 1839

Answers (3)

kolrabi
kolrabi

Reputation: 554

The documentation is very confusing but I think I found the problem. DoModal internally calls ::DialogBox(), one parameter of which takes a HWND named hWndParent. From the documentation:

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

The keyword here is the word "owns". The section about owned windows confirms this:

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.

So we actually talk about the owner window instead of its parent. This makes sense as the dialog is a free floating window and not part of a window hierarchy as "parenthood" would imply.

You can get the owning window by using:

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

Upvotes: 2

Danil
Danil

Reputation: 895

I've got two versions of the same application and one of them disables all parent popup windows as it should when DoModal is called. Second version disables only top-level CMainFrame and real parent is stay enabled so I can call modal dialog twice and more.

This happen in CWnd::GetSafeOwner_, line : hWnd = ::GetLastActivePopup(hWnd);

Firsts version return real parent while second version return CMainFrame. I've spent one day and could not find the cause of such behaviour. However I've found workaround:

When DoModal is called it Disable CMainFrame so I can disable it's children also:

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);
    });
}

Upvotes: 0

Tom Tom
Tom Tom

Reputation: 1209

I had a similiar issue. I was wondering why GetParent() return always a different CWnd*.

The right solution is simple, just pass the desired pWnd to the dlg Constructor.
It will be stored in the CDialog member variable m_pParentWnd.
Then you can always get the passed pWnd with this member variable in your Dialog.

//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
    ...
  }
 ....
}

Upvotes: 1

Related Questions