Dialog-Based Applications
A dialog-based MFC application uses a CDialog-derived class as its entire main window instead of a CFrameWnd with a menu bar and client area — the App Wizard generates a CWinApp::InitInstance() that constructs the dialog with DoModal() and treats the dialog's return as the reason to exit, making this template ideal for utilities, configuration tools, and simple front ends that don't need document/view architecture or multiple windows.
Cricket analogy: It's like a T10 exhibition match format replacing a full five-day Test — same sport, but a single compact fixture stands in for the whole tournament structure of frames, sessions, and days.
How the App Wizard Wires DoModal Into InitInstance
When you generate a dialog-based project, InitInstance() constructs your CDialog-derived class on the stack and immediately calls DoModal(), which blocks and pumps its own nested message loop until the dialog is dismissed via EndDialog(); the wizard-generated code then typically returns FALSE from InitInstance() regardless of the dialog's result, because once DoModal() returns, there is no more UI to run, so the application must terminate.
Cricket analogy: It's like the umpire's light going up for a no-ball review — play pauses entirely and waits for the third umpire's single verdict before the match can resume in any direction.
Control Data Exchange in the Dialog
DoDataExchange and DDX/DDV
Dialog-based apps rely heavily on DDX (Dialog Data Exchange) and DDV (Dialog Data Validation), generated inside an overridden DoDataExchange(CDataExchange* pDX) function: DDX_Text, DDX_Check, and similar macros copy values between member variables and control HWNDs, while DDV_MinMaxInt and friends enforce range constraints, and UpdateData(TRUE) or UpdateData(FALSE) triggers the exchange in the requested direction.
Cricket analogy: It's like a scorer cross-checking the manual scorebook against the electronic scoreboard after every over, pulling numbers in whichever direction needs correcting to keep both in sync.
// CMyDlg — the entire application's UI
class CMyDlg : public CDialogEx
{
public:
CMyDlg(CWnd* pParent = nullptr) : CDialogEx(IDD_MYDLG_DIALOG, pParent) {}
enum { IDD = IDD_MYDLG_DIALOG };
CString m_strName;
int m_nAge;
protected:
virtual void DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_NAME, m_strName);
DDX_Text(pDX, IDC_EDIT_AGE, m_nAge);
DDV_MinMaxInt(pDX, m_nAge, 0, 120);
}
afx_msg void OnBnClickedOk()
{
UpdateData(TRUE); // pulls control values into m_strName / m_nAge
if (m_strName.IsEmpty()) { AfxMessageBox(_T("Name required")); return; }
CDialogEx::OnOK();
}
DECLARE_MESSAGE_MAP()
};
// App.cpp
BOOL CMyApp::InitInstance()
{
CMyDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK) { /* use dlg.m_strName, dlg.m_nAge */ }
return FALSE; // no message loop to run after the dialog closes
}
UpdateData(TRUE) validates and copies control values into member variables; UpdateData(FALSE) does the reverse, pushing member variable values back out to the controls. Call the right direction depending on whether you just changed the data programmatically or need to read what the user typed.
Returning TRUE instead of FALSE from InitInstance() in a dialog-based app leaves the framework expecting a main window to keep pumping messages for, but the dialog is already destroyed once DoModal() returns — this mismatch is a classic source of dialog-based apps that appear to hang or exit oddly.
- A dialog-based app uses CDialog/CDialogEx as its entire UI, with no CFrameWnd or menu-driven main window.
- InitInstance() constructs the dialog and calls DoModal(), which blocks until EndDialog()/OnOK()/OnCancel() fires.
- InitInstance() should return FALSE after DoModal() returns, since there's no further message loop to run.
- DoDataExchange() with DDX_* macros moves data between member variables and control HWNDs.
- DDV_* macros validate exchanged data, such as enforcing a numeric range.
- UpdateData(TRUE) reads from controls into variables; UpdateData(FALSE) writes from variables to controls.
- This template suits utilities and simple tools that don't need document/view or multiple top-level windows.
Practice what you learned
1. What does InitInstance() typically do in a dialog-based MFC application?
2. Why does InitInstance() return FALSE after DoModal() returns in a dialog-based app?
3. Which function pulls values from dialog controls into their bound member variables?
4. What is the purpose of DDV_MinMaxInt in DoDataExchange()?
5. What does DoModal() return while it is running?
Was this page helpful?
You May Also Like
Creating Windows with MFC
How MFC's CWnd/CFrameWnd hierarchy and CWinApp::InitInstance replace manual Win32 window registration and message-loop code.
Modal vs Modeless Dialogs
The difference between MFC's blocking DoModal() dialogs and non-blocking Create()-based modeless dialogs, including lifetime management with PostNcDestroy.
MFC Controls Overview
A tour of MFC's C++ wrapper classes for Windows common controls, how to bind them via DDX_Control, and practical examples with CListCtrl and CComboBox.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics
Microsoft TechnologiesMVVM Design Pattern Study Notes
.NET · 30 topics