Make Modal Dialogs Behave Like Modeless Dialogs 

Description

This template class simulates the behaviour of a modeless dialog while allowing some of the programmatic control of a modal dialog. When modal dialog are closed control is immediately returned to the caller of the DoModal member function: 

CMyDialog dlg;

if( dlg.DoModal() ) { ... }

However, the same can not be said of modal dialogs where the Create/ShowWindow member function pair need to be used in order to display the dialog. 

CMyDialog dlg;

dlg.Create( IDD_MY_DIALOG );

dlg.ShowWindow();

...

if( you receive some message that the non-modal has closed ) 

{

...

}

The above code segment creates and activates a non-modal dialog. How and when you get control back generally involves some rather tricky programming - in other words, it's not nearly as straight-forward as using a modal dialog. 

Usage

NonModalDialogmyDlg( AfxGetMainWnd() );

myDlg.DoModal();

...

class CWnd;

template class NonModalDialog 

: public ModalDialog

{

public :

 NonModalDialog( CWnd *pParent ) 

 : ModalDialog( pParent ) { }

 virtual int DoModal();

 virtual void EndModalLoop( int );

protected:

 int m_nStillActive;

};

template 

inline int NonModalDialog::DoModal()

{

 MSG l_objMessage;

 CWinThread* l_pThread = AfxGetThread();

 ASSERT_VALID( l_pThread );

 Create( ModalDialog::IDD );

 ShowWindow( SW_SHOW );

 m_nStillActive = 1;

 //--------- Thanks to Microsoft. This block 

 //--------- is from CWinThread::Run

 // from Thrdcore.cpp, with appropriate changes.

 ASSERT_VALID(this);

 // for tracking the idle time state

 BOOL l_nIdle = TRUE;

 LONG l_nIdleCount = 0;

 // acquire and dispatch messages until 

 // a WM_QUIT message is received,

 // or the dialog box is closed.

 for (;;) 

 {

  // phase1: check to see if we can do idle work

  while( l_nIdle && !::PeekMessage( &l_objMessage, 

                                    NULL, 

                                    NULL, 

                                    NULL, 

                                    PM_NOREMOVE ) ) 

  {

   // call OnIdle while in bIdle state

   if( !l_pThread->OnIdle( l_nIdleCount++ ) )

    l_nIdle = FALSE; // assume "no idle" state

  }

  

  // phase2: pump messages while available

  do 

  {

   // Relent control back to Windows if the dialog 

   // box has closed.

   if( !m_nStillActive )

    return m_nModalResult;

   if( l_objMessage.message == WM_SYSCOMMAND 

   && l_objMessage.wParam == SC_CLOSE )

    OnCancel(); // Close the dialog box first.

   // pump message, but quit on WM_QUIT

   if( !l_pThread->PumpMessage() )

    return l_pThread->ExitInstance();

   // reset "no idle" state after pumping 

   // "normal" message

   if( l_pThread->IsIdleMessage( &l_objMessage ) )

    l_nIdle = TRUE, l_nIdleCount = 0;

  } while( ::PeekMessage( &l_objMessage, 

                          NULL, 

                          NULL, 

                          NULL, 

                          PM_NOREMOVE ) );

 }

 ASSERT(FALSE);  // not reachable

 //---------------------

}

template inline void 

NonModalDialog::EndModalLoop(int p_nResult)

{

 m_nStillActive = 0;

 ModalDialog::EndModalLoop( p_nResult );

}