Introduced way back in Delphi 2009 the TTaskDialog (defined in Dialogs.pas) implements task dialogs. Task dialogs first appeared in Windows Vista and are used in later Windows versions. In essence, a task dialog is similar to, while much more flexible and parameter-rich than the standard message dialog. You’ve surely seen such fancy dialogs in action: those containing message title and text (content), icons, push buttons, radio buttons, expandable footer area and more.
In Delphi we have several options (including ShowMessage, MessageDlg, Application.MessageBox and some more) when it comes to displaying some modal message to the user. I’m rarely using ShowMessage and Application.MessageBox as both are not as flexible as MessageDlg (actually ShowMessage internally calls MessageDlg).
MessageDlg: Bruce Banner or Hulk ?
Using MessageDlg can result in 2 different displays of the actual message dialog. What will get displayed (and more importantly how) to the user is dependent on several factors including the following: Windows version your application is running on, if the application was built including runtime themes and if Windows uses themes.
If your application is running on Windows XP, MessageDlg internally creates and displays a standard Delphi form (though set to look and work as a dialog). If your application is running on at least Windows Vista (therefore Windows Vista, 7, 8, 10, etc) and runtime themes are enabled and used by Windows, MessageDlg will internally create the shiny task dialog! Actually, the TaskDialogIndirect API call will be made. Even though this beast of a function has many parameters and options, MessageDlg will only take advantage of a few (title, text, buttons).
Finally, you end up simply using MessageDlg and Delphi determines if an old school dialog form is to be created or the new more nicer task one. Problem solved, let’s move on to other bugs… Well, not so fast!
TaskDialog Width & Long Text Truncation
One of the nasty features of TaskDialog internal implementation is that it will try to determine on its own what should be the width of the dialog. The text you specify to be displayed will be wrapped and displayed in several lines. This is, of course, something you would expect.
However! If the text to be displayed is constructed entirely of non-breakable characters (no spaces and alike) and is longer than some 50 (or so) characters, the display will get truncated and ellipses will be injected into the final display!?! TaskDialogs do not grow in width if “more” text is to be displayed – they grow in height and truncate/ellipsesize the message text. Old school dialog form on Windows XP will grow in width until it reaches screen size – and will not truncate the message for the user in any way!
Truncation / Ellipsesization Visualized
I’m running this on Windows 7, themes enabled.
I need to display the full file name of a file where the path does not contain any spaces (which seem to be default “wrap here” characters). Let’s pretend this file should be displayed (has some 250 characters, no intervening spaces) in a dialog:
const LongFileName = '\\server\sub-folder-name\folder0123456789folder0123456789\another-folder\morefolders\a-directory\another-directory\morefolders\morefolders\a-directory\another-directory\morefolders\a-directory\another-directory\somefile-using-hypens-in-long-filename.txt';
First, using the TTaskDialog component and only setting a few properties:
TaskDialog1.Caption := 'TaskDialog1'; TaskDialog1.CommonButtons := [tcbOk]; TaskDialog1.Text := LongFileName; TaskDialog1.Execute;
Trying with MessageDlg as
MessageDlg( Format('This file has a very long path: %s', [LongFileName]), mtInformation, [mbOk], -1);
Proof that MeesageDlg uses TaskDialog internally 🙂
Btw, you cannot set the width of the MessageDlg. Neither the “TDF_SIZE_TO_CONTENT” seems to help.
I Don’t Need (read: Want) No Truncation!
I really, really want to display the entire file path to the user with no truncation and ellipses.
Let’s try using the WrapText (SysUtils.pas) function:
MessageDlg( Format( 'This file has a very long wrapped path: %s', [WrapText(LongFileName)]), mtInformation, [mbOk], -1);
Better! Note that WrapText has 2 overloads and the more simple one has a property “MaxCol” which defaults to 45 (have no idea why).
However, 45 is not enough, I want the line to be some 80 or so characters, so trying with the following
MessageDlg( Format( 'This file has a very long wrapped path: %s', [WrapText(LongFileName), 80]), mtInformation, [mbOk], -1);
Oh no! Again, truncation and ellipses – why oh why?!
Finally, after spending too much time on all this I’ve decided for the next option as the kind-of-I-can-live-with-it best one:
UseLatestCommonDialogs (not in this occasion, please)
Getting away from the whiny new task dialog and disabling UseLatestCommonDialogs:
UseLatestCommonDialogs := false; MessageDlg( Format( 'This file has a very long wrapped at 80 path: %s', [WrapText(LongFileName, 80)]), mtInformation, [mbOk], -1); UseLatestCommonDialogs := true;
I’m not too happy with this – as the old school/style dialog is displayed – but I simply have to show the full file path to the user: no truncation or ellipses are allowed for me.
Do you have any idea how this can be better solved?
(I’m not looking for another 3rd party solution or some special one-time workarounds)
I had the same effect on TStatusbar which is limited to 127 on WinNT..XP. So I wrote my own.
May be change cxWidth or set TDIF_SIZE_TO_CONTENT flag in the TaskDialogIndirect call structure?
See comments in http://msdn.microsoft.com/en-us/library/windows/desktop/bb787473.aspx
@IL: Thanks, but I’d like to avoid messing with the VCL source. Note however that TDIF_SIZE_TO_CONTENT is already set (look at Delphi implementation source), still the long text is truncated.
Looks like Microsoft’s violation of very own Visual Guidelines for text (;
Though there is no plenty of space available in the TaskDialog.
I fear that UseLatestCommonDialogs is not thread or process safe…
I did not looked the VCL code, but probably is something related to the Static Control Styles being used by the Task DIalog function.
This MSDN link shows that a Static with SS_WORDELLIPSIS would have a similar behavior to what you are seeing.
Also, this remembered me of a Raymond Chen’s post:
Great workaround! This is an annoying reality of MessageDlg… You helped me big time! Thanks!
What’s your final workaround? I’m facing the same problem too now. Thanks.
As described in the post – to use UseLatestCommonDialogs and set it to False.
Thank you! I tried TaskDialog that was failed instead of MessageDlg when I set UseLatestCommonDialogs to false. I will use MessageDlg to see the results.