Question

I have a GUI window in WTL that runs inside a thread inside a CMessageLoop instance which has been added to the application instance and runs. Now, inside a button handler within the main GUI I create a new window. Once I click that button and create the window and try to post the quit message to the main GUI loop. The code:

Main window, has its own thread:

    CMessageLoop theLoop;
    _MyppModule.AddMessageLoop(&theLoop);
    if(m_pMyDlg == NULL) {
        m_pMyDlg = new CMyDlg();
        if(!IsWindow(*m_pMyDlg))
        {
            m_pMyDlg->Create(NULL);
            m_pMyDlg->ShowWindow(SW_SHOW);
            nRet = theLoop.Run();
            _MyppModule.RemoveMessageLoop();
        }
    }

Button handler & child window creation:

LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{

     ChildWindowDlg childDlg;
     childDlg.Create(m_hWnd);

     childDlg.ShowWindow(SW_SHOW);

     CMessageLoop _loop;
     );

     _loop.Run();
     ::DestroyWindow(childDlg);

     return S_OK;
}

Now, if I click the Close button in my MyDlg window the button's handler will get called, inside it I do ::PostQuitMessage but that never reaches the theLoop messageloop from the first code snippet. This happens after I exit the second loop, so _loop gets destroyed and the child dialog is destroyed. What is happening here?

Was it helpful?

Solution 2

The second code snippet is totally unnatural. If your goal is to have a window popped up, then closed and and then you want to complete execution of your button click handler, then modal dialog is what you need:

LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, 
                                BOOL& bHandled)
{
     ChildWindowDlg childDlg; // Add constructor parameters if needed
     // Additional initlaization calls might go here
     const INT_PTR nResult = childDlg.DoModal(m_hWnd); // DoModal handles it all
     if(nResult == IDOK) { ... } // Hey's we even have result coming from `EndDialog`
     return 0; // No S_OK here
}

No message loops, no PostQuitMessage, no separate window creation/destruction calls needed. This is what modal dialogs are for.


If you don't want to block "calling" window, and the idea is to have both master and slave windows running side by side (or, one is a part of another, anyway both to be responsive at the same time), then you don't want to block your message handler. The handler will create window and set it up (.Create, .ShowWindow) and then exit from OnButtonClicked function.

Both windows are created, both are alive and have their message sent to them by top level message loop. This is the correct approach, you don't normally need more than one message loop per thread. Sometimes it might make sense for specific operations, but this is really rare. Windows are passive instances. They respond to messages with their message handlers. A thread message loop serves all thread windows, because what it does is DispatchMessage API call, which in turn looks for target window, takes its WndProc and calls it handing message details in.

OTHER TIPS

You have two message loops here, the child's one is nested. On the other hand, the message queue is one per thread, and is pumped by the most inner message loop (with GetMessage). So, WM_QUIT message gets retrieved by the inner message loop inside CMyDlg::OnButtonClicked.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top