Windows Vista COMCTL32.dll v6 TaskDialog
PSTaskDialog
- Windows Forms Emulated TaskDialog
(Spot the difference!)
Introduction
After wasting innumerable hours hunting around the internet like a rabid squirrel for a way of using the Vista TaskDialog on pre-Vista versions of Windows, I decided to write one myself. "Necessity is the mother of invention." As I frequent The Code Project's website whenever I need help, I figured it was about time that I gave something back to the community. Hence, this article.
Background
Basically, I wanted a class that would wrap the TaskDialog
so that on a Vista machine, it would invoke the native TaskDialog
in COMCTL32.dll v6 (which ships with Vista), while on pre-Vista machines, it would emulate the TaskDialog
with a near identical substitute. Massive credit must go to KevinGre for his superb article "TaskDialog for WinForms," which wraps the COMCTL32 TaskDialog
API. The only changes made to his code were as follows:
- Prefixed
class
/enum
/struct
names with "VistaXxxx" (e.g. TaskDialog
-> VistaTaskDialog
) for the sake of clarity - Implemented the bug fix for x64 machines mentioned in the comments section at the bottom of his article
This project takes Kevin's work a step further, in that the TaskDialog
is no longer restricted to Windows Vista. You can now use the same code to display a TaskDialog
without worrying about the Windows version.
Using the Code
The namespace for this project is PSTaskDialog
(Pioneer Software is my company) and the only class that we really need to know about is the static public class cTaskDialog
(conveniently located in cTaskDialog.cs). The cTaskDialog
class contains a number of static public
methods to execute a TaskDialog
. The principle method is ShowTaskDialogBox
. I say "principle" because this is the routine that does all the work and displays either the Vista TaskDialog
or the emulated version. All the other methods in cTaskDialog
end up calling this method to invoke the TaskDialog
.
static public DialogResult ShowTaskDialogBox(IWin32Window ParentWindow,
string Title,
string MainInstruction,
string Content,
string ExpandedInfo,
string Footer,
string VerificationText,
string RadioButtons,
string CommandButtons,
eTaskDialogButtons Buttons,
eSysIcons MainIcon,
eSysIcons FooterIcon)
Example 1: Using the Full ShowTaskDialogBox Method
DialogResult res =
PSTaskDialog.cTaskDialog.ShowTaskDialogBox(this,
"The main instruction text for
the TaskDialog goes here.",
"The content text for the task
dialog is shown here and the
text will automatically wrap as
needed.",
"Any expanded content text for
the task dialog is shown here
and the text will automatically
wrap as needed.",
"Optional footer text with an
icon can be included",
"Don't show me this message
again",
"Radio Option 1|Radio Option 2|
Radio Option 3",
"Command Button 1
|Command Button 2\nLine 2\nLine 3
|Command Button 3",
PSTaskDialog.eTaskDialogButtons.
OKCancel,
PSTaskDialog.eSysIcons.
Information,
PSTaskDialog.eSysIcons.Warning);
Here's a screenshot of the above (this is on Vista running in Emulation mode).
A few things to note:
- The
string RadioButtons
and string CommandButtons
parameters are pipe (|
) delimited string
s containing each item for the radio buttons and command buttons respectively. - Sending in an empty
string
(""
) to some of the parameters will disable (i.e. hide) certain features of the TaskDialog
, namely:
ExpandedInfo
(the "Show details" section) Footer
(the bottom footer with the icon) VerificationText
(the "Don't show this again" check box) RadioButtons
(the radio buttons) CommandButtons
(the command buttons)
- In addition to the
DialogResult
return value, other information that you may need to know after executing the TaskDialog
are saved to the following static public
variables of cTaskDialog
:
VerificationChecked
(whether the "Don't show this again" CheckBox
was checked) RadioButtonResult
(0-based index of the selected RadioButton
) CommandButtonResult
(0-based index of the clicked CommandButton
)
Please note: I realize that some may feel that ref
parameters are a better way of retrieving these values as opposed to public static
methods of the cTaskDialog
class. Please feel free to change the code to your heart's content!
cTaskDialog
also has a few other static public
variables to consider:
EmulatedFormWidth
(default 450). This is the width of the emulated form. Vista seems to do some clever dynamic resizing of the TaskDialog
depending on its content. From my testing, 450 pixels seems to be a reasonable width (very similar to Vista in most cases) and it looks fine for most TaskDialog
scenarios. Change this value before executing the TaskDialog
if you wish. ForceEmulationMode
is a bool
that forces the emulated Windows Forms version of the TaskDialog
to be used on Vista machines (this is really just there for test purposes as there's no real reason to use the emulation mode when running Vista). UseToolWindowOnXP
(new in 1.02) is a bool
that makes the TaskDialog
use a ToolWindow
on pre-Vista systems. I think it matches the look of Vista a bit better than the thicker dialog caption bar. PlaySystemSounds
(new in 1.03) is a bool
that determines whether the TaskDialog
plays the default system sound (associated with the MainIcon
type) when it is displayed. This defaults to true
, so make it false
to suppress sounds.
Example 2: Showing a MessageBox
PSTaskDialog.cTaskDialog.MessageBox(this,
"MessageBox Title",
"The main instruction text for the
message box is shown here.",
"The content text for the message box
is shown here and the text will
automatically wrap as needed.",
"Any expanded content text for the
message box is shown here and the text
will automatically wrap as needed.",
"Optional footer text with an icon can be
included",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information,
PSTaskDialog.eSysIcons.Error);
Shown below is a screenshot of the above on Windows XP. Please compare this image against the top two in this article. The code is exactly the same to produce any of these dialogs.
Example 3: Showing an Even More Simple MessageBox
PSTaskDialog.cTaskDialog.MessageBox(this,
"MessageBox Title",
"The main instruction text for the
message box is shown here.",
"The content text for the message box
is shown here and the text will
automatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.OK,
PSTaskDialog.eSysIcons.Warning);
if (PSTaskDialog.cTaskDialog.VerificationChecked)
{
}
Example 4: Showing a Radio Listbox
PSTaskDialog.cTaskDialog.ShowRadioBox(this,
"RadioBox Title",
"The main instruction text for the
radiobox is shown here.",
"The content text for the radiobox is
shown here and the text will
automatically wrap as needed.",
"Any expanded content text for the
radiobox is shown here and the text
will automatically wrap as needed.",
"Optional footer text with an icon
can be included",
"Don't show this message again",
"Radio Option 1|Radio Option 2|
Radio Option 3|Radio Option 4|
Radio Option 5",
PSTaskDialog.eSysIcons.Information,
PSTaskDialog.eSysIcons.Warning);
Example 5: Showing a Command Button
PSTaskDialog.cTaskDialog.ShowCommandBox(this,
"CommandBox Title",
"The main instruction text for the
commandbox is shown here.",
"The content text for the commandbox
is shown here and the text will
automatically wrap as needed.",
"Any expanded content text for the
commandbox is shown here and the text
will automatically wrap as needed.",
"Optional footer text with an icon
can be included",
"Don't show this message again",
"Command Button 1|Command Button 2|
Command Button 3|Command Button 4",
true,
PSTaskDialog.eSysIcons.Information,
PSTaskDialog.eSysIcons.Warning);
Please take a look at the source code in Form1.cs in the TaskDialogTest folder to see exactly how cTaskDialog
can be used in your code.
Known Limitations
- I have not implemented the
ProgressBar
functionality in the emulated TaskDialog
, mainly because I have no need of it myself. It shouldn't be too hard to adapt the code if you wish to add this feature. - I have omitted the Shield icon that is available under Vista because
System.Drawing.SystemIcons
(used by the emulated form) doesn't have one. - Oddly, there is no Question icon available in the Vista
TaskDialog
, so the Vista TaskDialog
uses the Information icon instead on Vista when eSysIcons.Question
is specified.
History
- 12/11/2007 v1.0
- 12/11/2007 v1.01
- Visual adjustments to
RadioButton
layout and CommandButton
font to make it more "Vista-like" - Moved
public enum
s out of frmTaskDialog
(makes more sense)
- 15/11/2007 v1.02
- Added new
cTaskDialog.UseToolWindowOnXP
(see above for details); CommandButtons
now accept \n
in the string
to wrap to new line and display smaller text - A few more visual tweaks to make it look more "Vista-y" (if that's even a word?!)
- 25/11/2007 v1.03
- Added new
cTaskDialog.PlaySystemSounds
(thanks to logan1337) - "Main Instruction" text and Command Button text is now painted with
ClearTypeGridFit
text rendering for an even more Vista-like appearance (thanks to Thorsten Dittmar)
- 06/07/2009 v1.04
- The
public
routines can now all take an IWin32Window
Owner as the first parameter. This gives more control over the parenting of the TaskDialog
both in Vista (or Windows 7) and XP (thanks to grahamoneale). I've added plenty of overloaded routines so that if the Owner is omitted, null
is presumed, however it is good practice to specify an Owner form - Implemented image resizing improvement (thanks to TheDesertFox)
- Improved Dispose code (thanks to veki-peki)
CommandButton
can now be used as a standalone button (thanks to SDragon42)- Accelerator keys are now drawn correctly (thanks to Member243669)