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:

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:

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)

Can't build. none of this are defined MB_CONTINUEABORT,MB_SKIPSKIPALLCANCEL,MB_IGNOREIGNOREALLCANCEL,MB_DONT_DISPLAY_AGAIN,MB_DONT_ASK_AGAIN,MB_DEFAULT_CHECKED,MB_YES_TO_ALL,MB_NO_TO_ALL,MB_RIGHT_ALIGN,MB_NO_SOUND,MB_DEFBUTTON5 and MB_DEFBUTTON6

Like the release notes for 1.2 Lite says, then it no longer attempts to replace AfxMessageBox. It doesn't recognize the styles MB_OK, MB_YESNO, etc. because it would require special code to lookup the proper language strings.

First off, thank you very much for your program, It's very util for me. I've got a big problem is that if I use your version, my application aborts. I think it's because when I use the routine, the resource dialog is not loaded yet, so I decided to create the dialog dynamically. Do you know how?

First of all I want to say that the source code is very well written, and easy to understand and maintain. Excellent job you got my 5.

I needed to present a MessageBox with different buttons, than the predefined buttons in AfxMessageBox. No timers, No checkboxes, no extra resources, no registry settings.

I have taken your CMessageBoxDialog and stripped away everything but the ability to add custom buttons (Now less than 900 lines including comments). And fixed so the resource is created in memory instead of needing to add a dummy dialog to ones project, and fixed so buttons can be added with a simple text-string instead of having to create a text-resource first.

Would I be allowed according to the code-license, to release yet-another-messagebox implementation based on your code ?

On my message dialog I get a strange box that comes from the message title and goes off the end of the message box. How did it get there and how do I get rid of it? I am using Microsoft Visual Studio 2005
Version 8.0.50727.42 (RTM.050727-4200)
Microsoft .NET Framework
Version 2.0.50727

On Windows XP I noticed that CMessageBoxDialog comes up with pixelated fonts, while the app dialog itself is cleartyped. Does anyone know how to add ClearType drawing? Looking into the LOGFONT structure of the CFont in CreateButtonControls() you'll see that the lfQuality value is 0 (DEFAULT_QUALITY).

Thanks in advance.

PS: Did I mention that when I inserted a ::MessageBox() to compare the layout, it used the font smoothing?