Search code examples
delphiwindows-7

MessageDlg shows information icon instead of confirmation


On Win 7, MessageDlg shows information icon instead of confirmation icon (question mark). Here is the code:

MessageDlg('Are you sure you want to delete this file?'+ CRLF+ FileName, mtConfirmation, [mbYes, mbNo], 0)= mrYes

What am I doing wrong?


Solution

  • First, notice that a simple workaround is to use the Windows API MessageBox function instead:

    MessageBox(Handle, 'This is a test.', 'Test', MB_ICONQUESTION or MB_YESNO)
    

    MessageBox

    But why doesn't MessageDlg work? Well, MessageDlg does one of two possible things. It uses the Windows Vista+ Task Dialog, if possible, that is, it the OS is Windows Vista or later and themes are enabled and the UseLatestCommonDialogs global variable is true (the default). If not, the VCL actually creates a custom TForm and adds all buttons, labels, and icons manually (which is a bit odd if you ask me -- why not simply use MessageBox?).

    The last approach supports the question-mark icon. Indeed, try

    UseLatestCommonDialogs := false;
    MessageDlg('This is a test', mtConfirmation, [mbYes, mbNo], 0);
    

    MessageDlg

    But this looks so ugly! Please don't do this! It is stupid to create a custom message dialog instead of using the native OS dialogs!

    Unfortunately, however, the Task Dialog does not support the question-mark icon (as a pre-defined icon). This is not a restriction of the TTaskDialog wrapper, but a limitation of the Windows Task Dialog API. See the official documentation, for instance. There are TD_ERROR_ICON, TD_WARNING_ICON, and TD_INFORMATION_ICON, but no question-mark icon.

    Of course, the Task Dialog can use any icon. For instance, you can do

    if (Win32MajorVersion >= 6) and ThemeServices.ThemesEnabled then
        with TTaskDialog.Create(Self) do
          try
            Caption := 'Test';
            Title := 'Test';
            Text := 'This is a test.';
            CommonButtons := [tcbYes, tcbNo];
            CustomMainIcon.ReleaseHandle;
            CustomMainIcon.Handle := LoadIcon(0, IDI_QUESTION);
            Flags := [tfUseHiconMain];
            Execute;
          finally
            Free;
          end
      else
        MessageBox(Handle,
                   'This is a test.',
                   'Test',
                   MB_ICONQUESTION or MB_YESNO);
    

    Notice that I fall back on the old MessageBox should the Task Dialog API not be available.

    Task Dialog

    In principle, the MessageDlg function could use additional logic to handle the question-mark case separately, in a way that differs from the information, warning, and error cases. This would have made the mtConfirmation give the right icon even with the Task Dialog, at the expence of slightly more complicated, and less elegant, VCL code. Apparently, however, Embarcadero chose the simpler alternative of simply pretending that you asked for the information icon.

    Still, I wonder why Microsoft chose not to include a TD_QUESTION_ICON constant in the API. Perhaps this icon is discouraged in their latest UI guidelines?