Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Enhanced MFC Message Boxes

0.00/5 (No votes)
22 Oct 2010 1  
How to replace the standard MFC message box with an enhanced version

Last update: 2010-10-20

Enhanced MFC message boxes

The Problem

Windows applications often use message boxes for asking the user for some actions or for displaying information messages. From week to week, more applications are getting published, which contain nice message boxes with checkboxes like "Do not display this message again" or "Do not ask this question" again, with which the user is able to customize the application behavior and to get rid of message boxes, which he always wants to answer in the same way.

I also wanted to offer this to the users of my applications. What features should be supported?

  • The message boxes should support some new style (the MB_??? flags used in a call of AfxMessageBox).
  • Such message boxes should be entirely written in MFC to enable other MFC developers to make quick and easy customization without having to know much about Windows API calls, just by using the standard MFC classes.
  • The new message boxes should support the checkboxes mentioned above and should manage automatically to save the state of the checkbox and the answer of the user and not to display the message box again, if the user didn't want it to appear again.
  • The message boxes should also be easy to integrate into existing applications. In existing applications, I didn't want to change every line of code containing a call to AfxMessageBox to something else. I'd just like to add a few lines of code and all messages boxes should appear in the new way.

Existing Solutions

At CodeProject, there are currently two different interesting solutions for modifying and enhancing the standard Windows message boxes, which can be invoked from MFC based applications by using the AfxMessageBox method:

Although these solutions work fine, there were a few problems, because of which I was forced to offer a third solution:

  • Both solutions can be used in MFC based applications, but offer only little or even no support for the standard MFC classes. For example, in one application, all dialogs are not derived from the MFC CDialog class directly, but from another class, which draws a custom skin for the dialog instead of the standard skin. If I want to use the message boxes provided by the two solutions mentioned above in this case, I have to apply many changes in the source code. My solution is entirely based upon MFC classes. It can therefore be easily modified and is for people like me, who enjoy using MFC and do not want to get deep into Windows API calls and is more easy to understand.
  • The XMessageBox class supports "Do not ask again" or "Do not display again" checkboxes in the displayed message boxes. This feature is also supported by my CMessageBoxDialog class. The problem with the XMessageBox class from my point of view has been, that the state of the checkboxes, which has been stored in the registry, was stored there in a way, which is not the standard way by using the WriteProfileInt or GetProfileInt methods of the CWinApp class. This might seem to be only a little problem, but I'd like to get the values stored in the same places as all other profile values are stored automatically by the MFC framework.
  • At last, the layout of the message boxes generated by the two classes mentioned above didn't seem to me quite the way I'd like it to be, therefore I changed it a little bit.

How to Use CMessageBoxDialog

The Simple Way

The simple way to use the new message box is to change nothing in your application. All your calls to AfxMessageBox(...) remain just the way they are already. You just have to overwrite the method DoMessageBox in your application class, which is derived from CWinApp. Use the following code to overwrite the method:

int CYourApplication::DoMessageBox ( LPCTSTR lpszPrompt, UINT nType, 
    UINT nIDPrompt )
{
    // Create a handle to store the parent window of the message box.

    CWnd* pParentWnd = CWnd::GetActiveWindow();

    // Check whether an active window was retrieved successfully.

    if ( pParentWnd == NULL )
    {
        // Try to retrieve a handle to the last active popup.

        pParentWnd = GetMainWnd()->GetLastActivePopup();
    }

    // Create the message box dialog.

    CMessageBoxDialog dlgMessage(pParentWnd, lpszPrompt, _T(""), nType,
        nIDPrompt);

    // Display the message box dialog an return the result.

    return (int)dlgMessage.DoModal();
}

Now every time you use AfxMessageBox anywhere in your application, the new message box will appear. The new feature can simply be used by adding the new message box styles (the MB_??? flags) to your already existing message box flags. Your example, if you do a call like this:

int nResult = AfxMessageBox(IDS_ARE_YOU_SURE_TO_QUIT, 
    MB_YESNO | MB_ICONQUESTION);

To add the checkbox "Don't ask again" to the message box, simply change the call to:

int nResult = AfxMessageBox(IDS_ARE_YOU_SURE_TO_QUIT, 
    MB_YESNO | MB_ICONQUESTION | MB_DONT_ASK_AGAIN);

The Other Way

The other way of using the new message box is to directly create a dialog object. For details, please take a look at the header file of CMessageBoxDialog. The constructor will take the same parameters as the AfxMessageBox method. If you create the message box this way, you can also change the displayed icon to some other icon by using the SetMessageIcon method.

It's also required to create the message box this way, if you want to use the timeout feature, which can be activated by calling the SetTimeout method. A timeout is a countdown, which starts, when the message box is displayed. There are two modes for a timeout: The "un-disabled" or "enabled" timeout means, that the user can choose any button, but if he doesn't choose one, the default button will be assumed as being chosen, when the countdown is finished. The other mode, a "disabled" countdown is something like a nag screen. All buttons will be disabled, until the countdown is finished. After that, the user can click any button.

The New Styles and Return Values

Besides the standard MB_??? flags provided by Windows, the CMessageBoxDialog supports the following new flags:

  • MB_CONTINUEABORT: Display two buttons in the message box: "Continue" and "Abort".
  • MB_SKIPSKIPALLCANCEL: Display three buttons in the message box: "Skip", "Skip all" and "Cancel".
  • MB_IGNOREIGNOREALLCANCEL: Display three buttons in the message box "Ignore", "Ignore all" and "Cancel".
  • MB_DONT_DISPLAY_AGAIN: If you set this flag, a checkbox "Don't display this message again" will be displayed in the message box. If the user checks this checkbox, the result of the message box will automatically be stored in the registry. The next time, this dialog will be called through AfxMessageBox or the DoModal method of the CMessageBoxDialog directly, the former result will be returned. You as a developer do not have to care, whether the message box is actually displayed or not. You will receive the result, the user wants you to receive - no matter whether it's a direct input or it's the input stored in the registry, because the user didn't want to be asked again.
  • MB_DONT_ASK_AGAIN: This flag does the same as MB_DONT_DISPLAY_AGAIN, only the text of the checkbox will be another one: "Don't ask this question again" instead of "Don't display this message again".
  • MB_DEFAULT_CHECKED: If a checkbox is displayed, this box is not checked by default. If you add this flag, the checkbox will be marked checked as soon as the message box is displayed.
  • MB_YES_TO_ALL: If this flag is set and your message box contains a "Yes" button, an additional button with the text "Yes to all" will be added to the message box.
  • MB_NO_TO_ALL: This flag does the same as MB_YES_TO_ALL, but it will add the button "No to all", if your message box contains a button named "No".
  • MB_RIGHT_ALIGN: If you specify this flag, the button in the dialog will be aligned on the right side of the message box (e.g. as it is done in the Windows Explorer) and will not get centered in the dialog.
  • MB_NO_SOUND: If you specify this flag, no standard sound will be played, if you open a message box.
  • MB_DEFBUTTON5 and MB_DEFBUTTON6: Because now there can be more than four buttons in a message box, these flags have been added to enable you to select another default button.

Because of the new buttons, there are also some new return values: IDYESTOALL, IDNOTOALL, IDSKIP, IDSKIPALL and IDIGNOREALL. They represent the new buttons and will be returned, if one of these buttons is clicked.

Other Methods

There are also some other public methods for the CMessageBoxDialog class, which are explained in the header file or the source code and should be easy to understand and use.

Just one method might be interesting: ResetMessageBoxes. If you call this method, all message box results, which have been stored in the registry, because the user checked the "Don't display again" or "Don't ask again" checkbox, are removed. Therefore all message boxes will be displayed again.

How to Use It with VC6/MFC6

To use the CMessageBoxDialog with VC6/MFC6, some minor changes need to be applied. Please take a look at this message for more information. Because I do not have VC6/MFC6 installed, I cannot provide a full download for this case, but I think it's very easy to customize and should be no problem.

History

2010-10-20: Version 1.2 lite

  • Added the feature that one can add buttons without needing a static string resource
  • Added the feature that the dialog is now dynamic (instead of having add a custom dialog resource)
  • Removed the feature of using a checkbox to remember choice (required access to settings/registry)
  • Removed the feature of using a timer to automatically choose (too complicated code)
  • Removed the feature of imitating the AfxMessageBox (Messsagebox styles require access to user32 resource to retrieve "Ok", "Cancel", etc.)

2004-03-01: Version 1.1a (Minor update)

  • License: Source code now may be used under the terms of the LGPL license, too
  • License: Added the full licenses to the ZIP archives

2004-02-29: Version 1.1 (Minor update)

  • Bug Fix: Added missing files to the ZIP archive
  • Bug Fix: Added support for the standard Windows flags MB_RIGHT and MB_RTLREADING, which were still missing
  • New Feature: Added the ResetMessageBoxes method to reset the message boxes
  • New Feature: Added the MB_DEFAULT_CHECKED flag
  • New Feature: Added the enabled and disabled timeout for the message boxes

2004-02-28: Version 1.0 (Initial release)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here