Dialog windows and WM_CLOSE

When you have a dialog based app, and you don’t want it to close, what most people do is to override the handler for the IDCANCEL button and comment out the call to CDialog::OnCancel() which calls CDialog::EndDialog(...) which then calls the EndDialog API call. Now this is all fine except that the dialog won’t close if you click the top-right [x] button or if you press Alt-F4, and this can be confusing to the end-user since all windows are expected to close if you attempt one of the above. The solution is to also handle the WM_CLOSE handler and to call CDialog::OnCancel() from it as shown below :-

void CDelMe03Dlg::OnBnClickedCancel()

void CDelMe03Dlg::OnClose()

If you are wondering about this behavior, what happens is that when the default dialog box procedure gets a WM_CLOSE message, it posts a BN_CLICKED (through WM_COMMAND) message to the dialog box passing IDCANCEL as the control id. Now this means that OnBnClickedCancel (or whatever you called it) gets called and since this does not call CDialog::OnCancel, the dialog just stays there like nothing ever happened.


28 thoughts on “Dialog windows and WM_CLOSE

  1. Hey Nish – thanks for the comment on my blog. I recently returned to the world of internet and blogging and noticed your comment! Browsed through yours and have to admit -Quite a bit of your blog raced above my head, not being a techie myself! πŸ˜‰

  2. Hi Nishant (Greetings from Texas),

    I noticed your modeless dialog post on CodeProject, and I figured you would be the man to answer my questions. This is probably the wrong thread, but it’s the closest I could find. I have a MSVS .NET 2003 C++ MFC (non-.NET or unmanaged) GUI from a CFormView class. I want to add a 2nd dialog (besides the main one) which I can open from the main dialog’s menu.
    I’ve added the dialog & menu button, but I can’t figure out how to access the 2nd dialog. I can’t find where the class for the 2nd dialog is. My first/main dialog is:

    class CAdHocGUIView : public CFormView{
    enum{ IDD = IDD_ADHOCGUI_FORM };…
    But how do I add in my IDD_2ndForm dialog (it doesn’t exist anywhere except Resource.h)? My 2nd problem is that I want to transfer some controls from the main dialog to the 2nd and it cuts-and-pastes ok, but when compile it says, “Error: no data exchange control with ID 0x041F” which I believe is the control ID that I moved.
    Do you know of a tutorial that’s already written for this? I know it’s fairly basic. and I apologize if my question bothers you. My main problem is finding where this stuff is in VS7 or where I should add the code.

    Thank you for your time,
    Jay Monnat

  3. Jay,

    In VS.NET 2003, after you add the dialog using the resource editor, you need to create the class files by right clicking on the project name in the class view and select add class. The type of class you want to add is an MFC class. It will then let you enter in the class name, file names, etc. The key part is that you need to select CDialog as the base class and enter in IDD_2ndForm into the dialog ID box. That will bind the new class to the dialog box you created using the resource editor. Once you’ve done that simply do the following to open it anywhere in you application.

    C2ndFormDialog newDialog;

    and you should be on your way.

  4. Hello Jay

    Pike has answered your first question; in addition to what he said, you also need to #include the header for the new dialog class in the cpp where you need to use it.

    For your second question, I am not sure how exactly you copy/pasted the controls; if you do it from the resource editor things should be fine. Do not copy/paste the code though, just copy/paste the controls. You’ll have to add any event handlers in the new dialog yourself.

  5. Hello,

    I had written the class into an existing .cpp & couldn’t get it to work. As Pike suggested, I just made a seperate class & that all works now. Thanks!
    As for the 2nd question of transferring over my controls from the main dialog to the 2nd “pop-up” dialog (from a menu choice) I’ve been trying to just cut-and-paste the controls from one to the other. They all paste in correctly, but at compile time I still get the “Error: no data exchange control with ID 0x041F” error. Is there somewhere to tell it that the dialog has changed? The only lines I can find with that particular control are:
    #define IDC_STATICLatLon 1055
    DDX_Control(pDX, IDC_STATICLatLon, m_staticLatLon);

    I don’t see anything linking it to a specific dialog. That’s just static text, so there’s no event handler that I know of. Do I have to completely rewrite all event handlers?
    A third question I noticed is in my IDR_MAINFRAME – Menu I added the lines in the menu I wanted and used the & to make accelerators. It shows the underlines on the appropriate letters & it looks good, but when I run the program the underlines/accelerators don’t appear or function.

    Thank you for the quick responses & help,

  6. Jay

    Do you get the error in your new dialog’s cpp file? Or your original dialog’s cpp file? The error basically means that, in your dialog resource, you’ve deleted the control, but you are still trying to do DDX with it

    As for the menu item underlines not coming, it’s a setting in 2K/XP that you can change. In XP, take Display Properties, Appearance tab, Effects, “Hide underlined letters for keyboard navigation until I press the Alt key” check-box

  7. Nish,

    I think the error is for the main cpp (mapGUIView.cpp) where all the DDX_Control lines are. If I add a control to the 2nd dialog it doesn’t add a DDX anywhere for it (that I can find), and if I cut-and-paste it it doesn’t change the code to reflect the control’s new location. Do you know where in the code it makes the associations so that I can change it to look at the new dialog, or where I should add the DDX lines for the controls on the 2nd dialog?

    Thanks for your help,

  8. Followup:

    I tried moving all the control lines from my main cpp file to the 2nd dialog class cpp file (CmapCoords.cpp & CmapCoords.h). I then instantiated a CmapCoords object in my main cpp onInit called mapCoord. It recognizes all the names & compiles, but when I try to change the variable, such as with:
    It recognizes everything to where I can put the . and it gives me all the options.
    But, when I try to compile I get “The thread ‘Win32 Thread’ (0x68c) has exited with code 3 (0x3).” errors. It doesn’t seem to like me trying to access the DDX in the object/other cpp file for the 2nd dialog. Maybe I’m just all confused, but I moved all the variables to the dialog class for easy access, but now I can’t seem to access them from the main cpp.

    Thanks again,

  9. Sorry to keep posting on your site, but I have better info on my error. The above error is in winocc.cpp line 247 and fails the following assertion:
    void CWnd::SetWindowText(LPCTSTR lpszString){
    ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));
    if (m_pCtrlSite == NULL)
    ::SetWindowText(m_hWnd, lpszString);
    so, I’m guessing when I transferred the controls to the 2nd dialog cpp I lost my m_hWnd “link.” How do I fix that?


  10. Part of the problem is that there is normally 3 options in a Dialog,
    OK, Cancel and |X| (with the occasional Apply).
    How are users mean’t to know that |X| == Close ?
    But what does Close really mean,
    1. do the OK routine ?
    2. do the Cancel and exit routine ?

    So the whole problem to me is that |X| is flawed for intuition.

  11. I red many of your articles. I like U much. Thank you for helping us through codeproject. Thanks alot. πŸ™‚ Have a nice day πŸ™‚

  12. Hi Hish,

    I have a problem which might be the reverse of the one described in the article. I have two modal dialogs in my application. They are similar – more or less the same properties in the resource editor, except ID and caption.

    The first one behaves “normal” but the second one does not react on the “|X|” nor key. I have to press the Ok button to release it. I turned your article upside-down – I have overwritten OnClose and delegated it to OnCancel(). Now I can use the “|X|” button but still does not work which probably is an indication that the problem is in OnCLose (?)

    Any help apreciated…


  13. Hello Jan

    How do you show 2 modal dialogs at the same time? Are they started by separate threads?

    There’s a bug associated with doing so that I’ve written an article on.

  14. Hi Nish,

    no, they are not shown at the same time. Each one is shown on pushing different uttons. The problem is that even if they seem to be similar (okay, one has a list control, the other one has a tree control) they behave different as described above.

    I think I just overlook something…


  15. Hi Nish,

    you mentioned your article … I read it already (“The singular non-modality of MFC modal dialogs”, right?) – and posted a question there. The article brought me here.

    Could you also have a short look at my question at the code project?

    Would be a hell of a help …


  16. Hi Nish,

    I fixed it! The problem was the following:

    The dialog has a button “Save…” which is disabled by default and only enabled if some element is selected in a tree. Unfortunately when I created the dialog I “reused” the default “Cancel” button. I changed the ID name to IDC_SAVE_BTN but of course the numeric value did not change – it was still 2 == IDCANCEL. Since the button was disabled, nothing happened on |X| or Esc.

    That’s a nasty thing, isn’t it?

    Greetings Jan

  17. i keep getting msg that i have dialog box open—i have no idea what that means or how to close it. i need to email some things from desk top but cannot get by this message—–what do i so to close??

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s