c++mfccdialog

MFC: X button on one window is closing a second window also


My application has several windows, each of a different CDialog-derived class.

Hitting the "X" button in the upper-right-hand corner of the window frame closes the window and calls PostNcDestroy.

For one of the four windows, though, it ALSO calls ANOTHER window's PostNcDestroy() in addition and makes that window invisible as well.

Any ideas?


Solution

  • SHORT ANSWER: The behavior was caused by setting m_pMainWnd AFTER creating all four windows. If it is set before creating the second window, the problem above no longer occurs.

    LONG ANSWER: the problem is that the windows ARE NOT SIBLINGS with each other. They are each a CHILD of the PREVIOUS.

    Parent of window 1 is value "0" (desktop). Parent of window 2 is window 1. Parent of window 3 is window 2. Parent of window 4 is window 3.

    My original problem report noted that window 4 mysteriously closed when window 3 was closed. So now the reason why is obvious. (Closing a window closes all its children too.) I subsequently discovered that closing window 2 caused 3 and 4 to close as well, which is also accounted for. (3 is 2's child so closes, and that makes 4, which is 3's child, close.) Finally, closing window 1 checks for unsaved work, and if none calls exit(). I assume that if this window didn't exit, the other windows would have all closed too.

    CDialog::Create() has default param NULL for its second arg pParentWnd, and NULL means parent "is set to the main application window." Stepping into CDialog::Create(), which calls CDialog::CreateIndirect(), which calls AfxGetMainWnd() I end up in CWinThread::GetMainWnd(). That method, if m_pMainWnd is not yet set, just returns CWnd::GetActiveWindow() which is the most-recently-created window.

    So: the source of the problem is that my app created four windows, THEN set m_pMainWnd. This is why window 3 was a child of window 2 (the active window at that point) 4 is a child of 3, and so on.

    By setting m_pMainWnd after creating window 1, then windows 2 3 and 4 are children of 1. So that gets rid of the "closing window 3 makes window 4 close too" problem.

    This still not quite what I needed, as it prevents window 1 from being brought in front of the other three windows. This is outside the scope of my original question, but here is the fix to that. Changing the Create() call to pass in GetDesktopWindow() explicitly seems to have gotten the app working as I wanted, with four windows independently able to close and be freely orderable in the window stack:

      Create( resource_ID, GetDesktopWindow() );
    

    I'm surprised this isn't a famous issue, as the documentation (as of VS2008Pro) for NONE of these functions actually explains what they actually do when m_pMainWnd isn't set, and moving that simple assignment to m_pMainWnd to the end of window creation would probably screw up ANY app that created more than two windows...