Modeless sibling dialog

Home
Serializing ASCII Data
Modeless child dialog
Modeless sibling dialog
The drag source
The MFC drop target
The TBTextTarget class
VC6 flat toolbar support

 

Create a modeless dialog box as sibling of the app's main window

Code Sample for this one is Interface.zip

It’s nearly as short as the child version of modeless dialogs

Follow these steps:

  1. Create a new dialog resource and use the Class Wizard for making a new CDialog based class COtherDropDialog
  2. In the class maintaining the modeless dialog (here it's CInterfaceView) add a member variable of type pointer to CWinThread and make sure you have a destructor:
    class CInterfaceView : public CView
    {
    ...
        CWinThread *m_pDlgThread
        ~CInterfaceView();
    ...
    }
  3. Use ClassWizard to create a new CWinThread-based class COtherDropDialogThread
  4. Override COtherRopDialogThread::InitInstance():
    If you forget to change the m_pMainWnd variable, the dialog will stay modal!
    BOOL COtherDropDialogThread::InitInstance()
    {
        COtherDropDialog dlg;
    
        m_pMainWnd = &dlg;
        dlg.DoModal();
        // returning false will make MFC doing most cleanup for us :)
        return FALSE;
    }
  5. In your appropriate message handler, do the following:
    void CInterfaceView::OnFileOthermodeless() 
    {
        // this block determines if we have our dialog already
        // displayed and not yet closed. You can't rely on 
        // m_pDlgThread to be NULL, because if you already have displayed 
        // and closed it, the pointer is not NULL but invalid	 
        if (AfxIsValidAddress(m_pDlgThread, sizeof(CWinThread)) &&
            AfxIsValidAddress(m_pDlgThread->m_pMainWnd, sizeof(CWnd)))
        {
            if (::IsWindow(m_pDlgThread->m_pMainWnd->GetSafeHwnd()))
            {
                 // the sibling dialog already exists. Just need to bring it to front
    m_pDlgThread->GetMainWnd()->SetWindowPos( &wndTop, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW); return; } } // OK, we need to create a new thread m_pDlgThread=AfxBeginThread( RUNTIME_CLASS(COtherDropDialogThread) ); }
  6. If you like your top-level window to have an icon displayed in the taskbar, add the following to COtherDropDialog:: OnInitDialog (ommited in the sample):
    BOOL COtherDropDialog::OnInitDialog() 
    {
        CDialog::OnInitDialog();
        m_hIcon = AfxGetApp()->LoadIcon(IDI_MYICON);
        SetIcon(m_hIcon, TRUE);
        SetIcon(m_hIcon, FALSE);
        // and all the other stuff
        //...
    }
  7. Don't forget to do the clean-up in the destructor:
    CInterfaceView::~CInterfaceView()
    {
        if (AfxIsValidAddress(m_pDlgThread, sizeof(CWinThread)) &&
            AfxIsValidAddress(m_pDlgThread->m_pMainWnd, sizeof(CWnd)))
        {
           // retrieve the threads main window
           CDialog *pDlg = (CDialog *)m_pDlgThread->m_pMainWnd;
    
           if (::IsWindow(pDlg->GetSafeHwnd()))
          {
        	    // make sure we have a CDialog-derived main 
        	    // thread window then terminate it
        	    ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(CDialog)));
        	    pDlg->EndDialog(IDCANCEL);
     
        	    // now give the thread some time to end, 
        	    // 2 second should be enough. You may be
        	    // able to use INFINITE as wait value, if you dare...
       	    WaitForSingleObject(m_pDlgThread->m_hThread, 2000);
        	    m_pDlgThread=NULL;
        	}
       }
    }