5
votes

Okay, so I will admit I have no knowledge of windows API or even MFC.

I've got an error window popping up when things go hairy (illegal character in a filename string) and I want the error box to be modal.

For the life of me I can't figure out why it crashes when it hits doModal.

Here is the code where I think this can be fixed. This code is in the event handler of a button in the main window.

CDialog *BadFileD = new CDialog();
BadFileD->Create(IDD_STATUS, this); 
BadFileD->DoModal();

Am I just being borderline retarded?

3
Rather than CDialog *BadFileD = new CDialog(); you should use CDialog BadFileD; especially when calling DoModal. It's simpler, and you don't have to worry about deleting the pointer when you're done.Mark Ransom

3 Answers

23
votes

MFC dialog divides two pattern, modal dialog and modeless dialog.

(1) Modal dialog usage:

CDialog dlg;
dlg.DoModal();

(2) Modeless dialog usage:

CMyDialog *pDlg = new CMyDialog();
pDlg->Create(ID_DLG, this);
pDlg->ShowWindows(SW_SHOW);

As you can see, we need a new pointer, but do not delete it. So, you need to do the following in our CMyDialog class:

  1. Add DestroyWindow() method in OnOk() and OnCancel().
  2. Add "delete this;" in PostNcDestroy() method.

If you do not, your code may cause a memory leak. BadFileD is a class member, and you delete it in destructor. I suggest use Modeless dialog.

10
votes

For display modal dialog you should use DoModal method only

CDialog *BadFileD = new CDialog(IDD_STATUS, this);
BadFileD->DoModal();

You can read remarks from article

1
votes

If you desire to just display an error message, it may be that rather than creating your own dialog you can just use AfxMessageBox(). See Microsoft Developer Network - AfxMessageBox.

If you want to do your own dialog box typically with an MFC project you would normally:

  • create a dialog box template using the resource editor
  • create a class encapsulating the dialog box with the class wizard implementing the behavior desired
  • insert the code to create and display the dialog box into the appropriate place

However with a simple dialog box that requires no supporting class for complex behavior you can skip the step of creating the encapsulating class with the class wizard and just use CDialog directly.

One question that needs to be answered is the lifetime of the dialog as well as whether it is to be modal or modeless. A modal dialog box requires the user to do something for the application to continue past the modal dialog box. A modeless dialog box does not block the application the way a modal dialog box does. There is also a system modal dialog box style.

Since you say it will be a modal dialog then the lifetime will be short so the entire construction, display, and destruction will probably be in a series of lines of code. For instance in a CView class with a command handler displaying a modal dialog box you might have:

void CViewThing::OnCommandMenuItem ()
{
    CDialog BadFileD(IDD_STATUS);
    int iRetStatus = BadFileD.DoModal();
    // check for status such as IDOK, etc.
    // do whatever is necessary.
}

What the above does is create a dialog box using the dialog resource template IDD_STATUS and displays it as a modal dialog box. Since it is local object, when the variable BadFileD goes out of scope, the dialog box destructor will be triggered and resources cleaned up for you.

You can also have a modeless dialog box. In the case of a modeless dialog box you need to consider the variable lifetime because as soon as the variable goes out of scope, the destructor will trigger and the dialog box will disappear.

So for a modeless dialog box being used with some view class, perhaps providing a tool box of some kind, the CDialog variable will be a member of the CView class which is using it. After the modeless dialog box is created, it is displayed or not by using the ShowWindow() member function of the CDialog class (actually a member of the CWnd class from which CDialog is derived).

void CViewThing::OnCommandMenuItem ()
{
    BadFileD.Create(IDD_STATUS, this);
    BadFileD.ShowWindow(SW_SHOW);   // display the dialog
}

and in the CViewThing class you would have a member variable CDialog BadFileD;.

Additional considerations

In all of the above examples we are not using pointers so that when the CDialog variable goes out of scope, either from exiting a member function or when the object using the dialog box is destroyed then the dialog box is as well. This object management is done for us.

One thing that you must take into consideration with a modeless dialog box is how to destroy it when you no longer need it.

Since a modal dialog box is usually a short term object, often created as a local variable on the stack, you normally just let it go out of scope to take care of everything dealing with destruction.

However the lifetime of a modeless dialog box requires that the DestroyWindow() method be used to destroy the dialog box when it is no longer needed. See Microsoft Developer Network - Destroying the Dialog Box.

A third usage scenario - embedding a dialog box

There is a third usage of a dialog box that sometimes comes in handy, embedding the dialog box into another window as a control.

In the above examples, the dialog box template specifies the WS_POPUP style for the dialog which is the standard style for a dialog box since the normal way that a dialog box is used is to display as a separate window.

However if you change the WS_POPUP style to WS_CHILD you can then embed the dialog box into another window as a control. You can remove the other style settings such as WS_SYSMENU, DS_MODALFRAME, and WS_CAPTION and remove the CAPTION line from the dialog template to further change the dialog box. So you will end up with something like:

IDD_STATUS DIALOGEX 0, 0, 435, 266
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    LTEXT           "this is some static text to display on this dialog.",IDC_STATIC,81,63,200,32
END

Then just use the resulting dialog box similar to how you would a modeless dialog box with ShowWindow().

If you need to reposition the embedded dialog box within its container window, you can use the SetWindowPos() method to do so. For instance the following would move the dialog box window within its containing window to be 20 pixels from the left and 10 pixels from the top of the containing window.

BadFileD.SetWindowPos(NULL, 20, 10, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER)