Click here to Skip to main content
Click here to Skip to main content

Vista Goodies in C++: Showing Friendly Messages with Task Dialogs

By , 29 Dec 2006
 

Contents

Introduction

In this Vista Goodies article, I will cover the new TaskDialog() API, which is designed to be a more user-friendly replacement for MessageBox(). TaskDialog() not only shows a nicer-looking UI, but it's also easier for the developer since it handles details like automatic loading of string resources.

This article is written for the RTM version of Vista, using Visual Studio 2005, WTL 7.5, and the Windows SDK. See the introduction in the first Vista Goodies article for more information on where you can download those components.

While it's always been easy to show simple messages using MessageBox(), it can be cumbersome to use at time, especially if your app is written with internationalization in mind and your UI strings are in a resource DLL: MessageBox() has no provision for loading string resources, unlike other APIs like DialogBox() which can be passed a resource ID. There is also the drawback that a message box can show only predefined sets of buttons; if you wanted to have a Retry button but not an Ignore button, you'd be out of luck.

While these shortcomings were addressed by MessageBoxIndirect(), that API still has the restriction on which buttons can be displayed. TaskDialog() solves that problem and provides a much easier-to-use and more flexible API.

The TaskDialog API

The TaskDialog() prototype is:

HRESULT TaskDialog ( HWND hWndParent, HINSTANCE hInstance,
                     PCWSTR pszWindowTitle, PCWSTR pszMainInstruction,
                     PCWSTR pszContent,
                     TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons,
                     PCWSTR pszIcon, int *pnButton );

The parameters are:

hWndParent
The window that will be the task dialog's parent. As with MessageBox(), this window is disabled while the task dialog is displayed. Pass NULL if you don't want the task dialog to have a parent (see this blog post by Raymond Chen on why passing GetDesktopWindow() is wrong).
hInstance
If any of the following parameters are the ID of a string or icon resource, set this parameter to the HINSTANCE of the module that contains the resources.
pszWindowTitle
The string to show in the task dialog's caption. This can either be a zero-terminated Unicode string or a string resource ID. When passing a resource ID, use the MAKEINTRESOURCE macro on the ID. (If you are building for the ANSI character set, use the Unicode macro MAKEINTRESOURCEW explicitly instead of MAKEINTRESOURCE.)
pszMainInstruction
The string to show at the top of the task dialog, beside the icon. This text is shown in a larger font and in a different color, making it appear like a heading in a document. As with pszWindowTitle, this parameter can be a C-style string or a string resource ID.
pszContent
The string to show in the body of the task dialog. This parameter can also be a C-style string or a string resource ID.
dwCommonButtons
A set of flags indicating which buttons to show in the dialog. To have multiple buttons, use the logical-or operator to combine the flags for the buttons you want. The possible flags are: TDCBF_OK_BUTTON, TDCBF_YES_BUTTON, TDCBF_NO_BUTTON, TDCBF_CANCEL_BUTTON, TDCBF_RETRY_BUTTON, TDCBF_CLOSE_BUTTON.

There is no restriction on which buttons can appear together; you can set as many flags in this parameter as you wish. If you pass 0, the default behavior is to just have an OK button. Note that the dialog will not be closeable using the Esc or Alt+F4 keys unless TDCBF_CANCEL_BUTTON is passed.

pszIcon
The resource ID of an icon to show in the task dialog. As with the string parameters, you must use the MAKEINTRESOURCE or MAKEINTRESOURCEW macro on the ID. You can also pass one of these predefined values to use a system icon: TD_ERROR_ICON, TD_WARNING_ICON, TD_INFORMATION_ICON, TD_SHIELD_ICON. TD_SHIELD_ICON displays the UAC shield () and should only be used to indicate a situation where the user will need to elevate to perform an administrative task. You can also pass NULL if you don't want any icon at all.
pnButton
A pointer to an int that is set to one of the following values to indicate which button the user clicks: IDOK, IDYES, IDNO, IDCANCEL, IDRETRY, IDCLOSE. If you pass TDCBF_CANCEL_BUTTON in dwCommonButtons, then *pnButton will be set to IDCANCEL if the user presses Esc or Alt+F4. If TaskDialog() fails, the value will be set to 0. You can pass NULL for this parameter if you don't need to know which button was clicked.

The return value from TaskDialog() is an HRESULT that indicates whether the function succeeds. It can fail if it is unable to load a resource, or in low-memory conditions.

If pszWindowTitle is NULL, the executable's filename is used for the caption text. pszMainInstruction or pszContent may be NULL if you don't want to have that piece of text in the dialog. Also, pszMainInstruction and pszContent can be multi-line strings; put a newline character ('\n') in the string to indicate a line break.

Note that the string parameters are always Unicode strings. As with many APIs added in XP and Vista, there is no version that accepts ANSI strings.

Examples using TaskDialog

Using TaskDialog with C-Style Strings

Let's start with an example that just uses hard-coded strings. The context in which we're showing this message is that our app has determined that an update is available, and we are asking the user if he wants to get the update now.

void CTheApp::OnUpdateAvailable()
{
HRESULT hr;
int nClickedButton;
LPCWSTR szTitle = L"Mike's AntiFluff Scanner",
  szHeader = L"An update for Mike's AntiFluff Scanner is available",
  szBodyText = L"Version 2007.1 of Mike's AntiFluff Scanner has been released." \
               L"Do you want to download the update now?";
 
  hr = TaskDialog ( m_hWnd, NULL,
                    szTitle, szHeader, szBodyText,
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    NULL, &nClickedButton );
 
  if ( SUCCEEDED(hr) && IDYES == nClickedButton )
    {
    // download the update...
    }
}

Here's the task dialog, showing the strings and buttons that we passed in:

We can also add an information icon with the pszIcon parameter:

  hr = TaskDialog ( m_hWnd, NULL,
                    szTitle, szHeader, szBodyText,
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    TD_INFORMATION_ICON, &nClickedButton );

Using TaskDialog with Resources

Now let's see how to use TaskDialog() when the strings and icon are in a resource DLL. We will need the HINSTANCE of the DLL that contains the resources. For this example, let's assume that the DLL has already been loaded, so all we need to do here is retrieve that handle. The way of doing this varies among class libraries; here are the functions you can call in ATL, WTL, and MFC:

  • ATL in VC 6 and WTL using a global CAppModule variable: _Module.GetResourceInstance()
  • ATL in VC 7 and later: _AtlBaseModule.GetResourceInstance()
  • MFC in VC 6: AfxGetResourceHandle()
  • MFC in VC 7 and later: AfxGetResourceHandle() and AfxFindResourceHandle()

First, let's replace the hard-coded strings with resource IDs:

HINSTANCE hinst = _Module.GetResourceInstance();  // this is the WTL method
 
  hr = TaskDialog ( m_hWnd, hinst,
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_TITLE),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_HEADER),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_BODY),
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    TD_INFORMATION_ICON, &nClickedButton );

And finally, let's add our own icon to the dialog:

HINSTANCE hinst = _Module.GetResourceInstance();  // this is the WTL method
 
  hr = TaskDialog ( m_hWnd, hinst,
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_TITLE),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_HEADER),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_BODY),
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    MAKEINTRESOURCE(IDI_TD_SAMPLE_ICON),
                    &nClickedButton );

Here's the final dialog with our custom icon:

That's all there is to it! While TaskDialog() is a snap to use, the dialog is still not much more complex than a message box. In the next article, I'll cover TaskDialogIndirect(), which has a lot more power and many more UI features.

Using the Sample App

The demo project for this article is a task dialog builder. You can enter the text you want to show in the caption, header, and body areas, along with the buttons and an optional icon:

The app then calls TaskDialog() with those parameters, so you can see the dialog in action:

Further Reading

Copyright and License

This article is copyrighted material, ©2006 by Michael Dunn. I realize this isn't going to stop people from copying it all around the 'net, but I have to say it anyway. If you are interested in doing a translation of this article, please email me to let me know. I don't foresee denying anyone permission to do a translation, I would just like to be aware of the translation so I can post a link to it here.

The demo code that accompanies this article is released to the public domain. I release it this way so that the code can benefit everyone. (I don't make the article itself public domain because having the article available only on CodeProject helps both my own visibility and the CodeProject site.) If you use the demo code in your own application, an email letting me know would be appreciated (just to satisfy my curiosity about whether folks are benefiting from my code) but is not required. Attribution in your own source code is also appreciated but not required.

Revision History

  • December 12, 2006: Article first published.
  • December 26, 2006: No content changes, just updated series navigation links.

Series navigation: « Using the New Vista File Dialogs | Using TaskDialogIndirect to Build Dialogs that Get User Input »

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

About the Author

Michael Dunn
Software Developer (Senior) VMware
United States United States
Member
Michael lives in sunny Mountain View, California. He started programming with an Apple //e in 4th grade, graduated from UCLA with a math degree in 1994, and immediately landed a job as a QA engineer at Symantec, working on the Norton AntiVirus team. He pretty much taught himself Windows and MFC programming, and in 1999 he designed and coded a new interface for Norton AntiVirus 2000.
Mike has been a a developer at Napster and at his own lil' startup, Zabersoft, a development company he co-founded with offices in Los Angeles and Odense, Denmark. Mike is now a senior engineer at VMware.

He also enjoys his hobbies of playing pinball, bike riding, photography, and Domion on Friday nights (current favorite combo: Village + double Pirate Ship). He would get his own snooker table too if they weren't so darn big! He is also sad that he's forgotten the languages he's studied: French, Mandarin Chinese, and Japanese.
 
Mike was a VC MVP from 2005 to 2009.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralGreat Article [modified]memberSpooky31 Jan '08 - 1:40 
When I first heard about the TaskDialog API I thought "Hmmph! Whats wrong with using a message box and forms?" Boy! was I ever wrong! This had made my life sooooo much eaisier, I use this as much as possible now even at those times when a simply YES/NO or OK/CANCEL type of decison is needed and a message box would do I still use a Task Dialog. Its just fun to use. Smile | :)
 
modified on Friday, February 01, 2008 1:35:44 PM

GeneralOrdinal 344 errormemberhector santos31 Dec '06 - 23:22 
Hi,
 
Running the sample TaskDialogSample.exe yields the popup error:
 
The ordinal 344 could not be located in the dynamic link library COMCTL32.DLL.

 
I tried this under XP/PRO SP2 and 2000/PRO SP4.
 
---
HLS
GeneralRe: Ordinal 344 errorsitebuilderMichael Dunn31 Dec '06 - 23:40 
There's a reason why this article is titled Vista Goodies Wink | ;)
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ
 
Ford, what's this fish doing in my ear?

General......memberCoolboy12320 Dec '06 - 16:54 
D'Oh! | :doh: D'Oh! | :doh: Poke tongue | ;-P
GeneralGreat articlememberAnna-Jayne Metcalfe12 Dec '06 - 21:50 
A simple but effective intro to a new API which very simply illustrates its advantages. Well done Mike!
 
By coincidence we're starting to look at this ourselves now, although as the product in question also has to run on Win2k and XP it will be implemented through a wrapper using GetProcAddress, so your article is rather timely. Smile | :)
 
Anna Rose | [Rose]
 
Linting the day away Cool | :cool:
 
Anna's Place | Tears and Laughter
 
"If mushy peas are the food of the devil, the stotty cake is the frisbee of God"

GeneralRe: Great articlesitebuilderMichael Dunn17 Dec '06 - 17:18 
Thanks Anna Smile | :) Look for my follow-up article on TaskDialogIndirect() which I am finishing up tonight.
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ

GeneralRe: Great articlesitebuilderMichael Dunn29 Dec '06 - 9:11 
Here's the new article btw:
http://www.codeproject.com/vista/VGTaskDialog2.asp[^]
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ
 
Ford, what's this fish doing in my ear?

GeneralRe: Great articlememberAnna-Jayne Metcalfe4 Jan '07 - 22:42 
Thanks Mike. Reading it now. Smile | :)
 
BTW while we were away over the Christmas break I took a close look at the code behind Maxime Labelle's Windows Vista-like Task Dialogs[^], as a result of which we now have a library (DLL or static) which will present similated task dialogs on Win2K/XP, and the real thing (TM) on Vista. That seems to be a pretty reasonable solution to the versioning dilemma.
 
The fact that we've tweaked the visual appearance of the simulated task dialogs to be pretty close to the native ones helps - the original code had some rather glaring inconsistancies.
 
By the way, do you know if TaskDialogIndirect() can be used for modeless task dialogs? We've one particular application which is just crying out for such a beast...
 
Anna Rose | [Rose]
 
Linting the day away Cool | :cool:
 
Anna's Place | Tears and Laughter
 
"If mushy peas are the food of the devil, the stotty cake is the frisbee of God"

GeneralRe: Great articlemvpMichael Dunn5 Jan '07 - 7:52 
No, task dialogs are always modal, just like message boxes are always modal. The user's selection is returned through out parameters of TaskDialog/Indirect - there'd be no way to return that info if the dlg were modeless.
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ

GeneralRe: Great articlememberAnna-Jayne Metcalfe25 Jan '07 - 22:17 
Thanks Mike - we came to the same conclusion ourselves a little while back, so instead wrote a mix-in class which gives a similar visual appearance to any dialog, as shown in this example[^].
 
When I get a little time I'm hoping to write an article on the subject. Smile | :)
 
Anna Rose | [Rose]
 
Linting the day away Cool | :cool:
 
Anna's Place | Tears and Laughter
 
"If mushy peas are the food of the devil, the stotty cake is the frisbee of God"

GeneralI love itmemberCoolboy12312 Dec '06 - 18:05 
From so many .Net 3.0 articles on Vista,I am so excite to see your articles on native C++ (such as WTL and so on...).
sorry for my poor English...
I am a chinese~~~~
I vote 5.
GeneralRe: I love itmemberyarp12 Dec '06 - 18:46 
So am I.
 
Yarp
http://www.senosoft.com/

GeneralRe: I love itsitebuilderMichael Dunn12 Dec '06 - 18:57 
谢谢您 Smile | :)
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ

JokeRe: I love itmemberAnton Afanasyev12 Dec '06 - 23:40 
If you use altavista to translate that to English, and select From: Chinese-traditiona,l it gives you two boxes and then the word "you". I guess it cenosors it Big Grin | :-D Laugh | :laugh:
 


Badger | [badger,badger,badger,badger...]

GeneralRe: I love itsitebuilderMichael Dunn13 Dec '06 - 8:58 
Try Simplified Chinese instead Smile | :)
 
--Mike--
Visual C++ MVP Cool | :cool:
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ

GeneralRe: I love itmemberAnton Afanasyev13 Dec '06 - 9:00 
I know. was just joking.;)
 


Badger | [badger,badger,badger,badger...]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 29 Dec 2006
Article Copyright 2006 by Michael Dunn
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid