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
NonModalDialog
myDlg.DoModal();
...
class CWnd;
template
: public ModalDialog
{
public :
NonModalDialog( CWnd *pParent )
: ModalDialog( pParent ) { }
virtual int DoModal();
virtual void EndModalLoop( int );
protected:
int m_nStillActive;
};
template
inline int NonModalDialog
{
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
NonModalDialog
{
m_nStillActive = 0;
ModalDialog::EndModalLoop( p_nResult );
}