I just had a strange error message from Visual Studio.NET when attempting to add a handler for WM_DESTROY to a C++ dialog class. It said:
Add/Remove of the function is impossible because the parent class code is read only
Odd. There's nothing read-only about any of this stuff.
It turns out that I'd previously had an OnDestroy function in that class, and (somehow) the ON_WM_DESTROY() macro had been left in the message map. This apparently confuses Visual Studio.
Just remove the old ON_WM_DESTROY() line, and it's happy to add a new one.
If you ask the MFC AppWizard to generate a dialog-based application, it generates code that looks like this:
BOOL CModalApp::InitInstance()
{
CModalDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
// TODO: Do something, based on nResponse (IDOK or IDCANCEL)
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
Unfortunately, this doesn't work properly if you have control bars in your dialog. This is because
DoModal doesn't use the standard MFC message loop. This means that OnIdle
is not called. If OnIdle is not called, then WM_IDLEUPDATECMDUI is not
sent, and the control bars aren't updated correctly.
![]()
CPropertySheet provides the SetWizardButtons function, allowing you to enable or disable the "Back" or "Next" buttons. It doesn't, however, allow you to disable the "Cancel" button.
Here's how:
CWnd *pCancel = GetParent()->GetDlgItem(IDCANCEL);
if (pCancel)
pCancel->EnableWindow(FALSE);
I'm adding a wizard to the program that I'm currently working on. The wizard walks the user through importing some information from a file. I'd like to be able to display the import progress as a seamless part of the wizard.
The program that I'm working on at the moment needs a wizard to walk the user through something. I copied over some files from a Wizard97 demo project that I wrote a while ago. It all seemed to be going well.
Except, that is, that IntelliSense in Visual Studio kept pretending that my classes were derived from CPropertySheet or CPropertyPage, rather than CPropertySheetEx or CPropertyPageEx respectively.
This was confusing.
It turns out that at some point between VC6 and VS.NET, Microsoft changed the definition of CPropertySheetEx and CPropertyPageEx in the MFC headers. They are the same -- one is a #define of the other.
The ON_COMMAND_RANGE and ON_UPDATE_COMMAND_UI_RANGE macros are useful when you want to treat a group of commands similarly. In this case, it's the commands for changing list view style. The command IDs must be contiguous, and you must specify the lower one first.
There's some discussion of this in Microsoft Knowledge Base Article Q141751.
This is initially quite simple:
class CCustomDrawDlg : public CDialog
{
// See Q141751
CDialogToolBar m_wndToolBar;
CStatusBar m_wndStatusBar;
// ...
int CCustomDrawDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create statusbar\n");
return -1;
}
return 0;
}