6

I am trying to create a MsgBox with three buttons and three outcomes, but am unable to see how I can create the third outcome? I currently have the following code for a two button MsgBox, which works perfectly:

if ((strExistingInstallPath <> '') and (strExistingVersion = '2.5.3')) then
begin
  if SuppressibleMsgBox('Setup has detected that ' + strMyAppName + ' ' + strExistingVersion + '.' + strExistingBuild + ' is installed.' + #13#10 + #13#10 +
    'The existing version must be removed before installing or upgrading to ' + strMyAppVersion + '.' + strMyAppBuild + '.' + #13#10 + #13#10 +
    'Would you like Setup to uninstall the existing version?',
    mbConfirmation, MB_YESNO, IDYES) = IDYES then
    begin
      Exec(GetUninstallString, '', '', SW_SHOW,
        ewWaitUntilTerminated, intResultCode);
      Result := True;
    end else
      begin
        MsgBox('The existing version must be removed first.' + #13#10 +
          'Setup is unable to continue. Setup will now exit.',
          mbError, MB_OK);
        Result := False;
      end;
end;

If I change the MB_YESNO to MB_YESNOCANCEL, I now get three buttons, Yes, No and Cancel. However, since the if statement is assigned to the MsgBox, I'm struggling to work out how to do an else if IDCANCEL then type statement. I tried to assign the ID constant returned by the MsgBox to a string and then create separate if statements for the string being equal to each ID constant, but this failed miserably. What am I missing here? Ideally, I would like the three buttons be labelled as Yes, No and Silent, so that the third button can be given a /silent parameter to prevent the uninstall prompt. So, is it possible to rename the buttons as well?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Robert Wigley
  • 1,917
  • 22
  • 42

2 Answers2

7

You could write multiple if statements, but you'd have to store the returned value into a variable and check that variable value. But as @Sertac mentioned in his comment, you can use a case statement, which better describes the aim in your code, for instance:

case SuppressibleMsgBox('Text', mbConfirmation, MB_YESNOCANCEL, IDYES) of
  IDYES:
  begin
    { user pressed Yes }
  end;
  IDNO:
  begin
    { user pressed No }
  end;
  IDCANCEL:
  begin
    { user pressed Cancel }
  end;
end;

Out of curiosity with multiple if statements it could be:

var
  MsgResult: Integer;
begin
  MsgResult := SuppressibleMsgBox('Text', mbConfirmation, MB_YESNOCANCEL, IDYES);

  if MsgResult = IDYES then
  begin
    { user pressed Yes }
  end
  else
  if MsgResult = IDNO then
  begin
    { user pressed No }
  end
  else
  if MsgResult = IDCANCEL then
  begin
    { user pressed Cancel }
  end;
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
TLama
  • 75,147
  • 17
  • 214
  • 392
  • Thanks. You second example with if statements is exactly what I had done previously, but using a string! Working now I realise that it should have been an integer. – Robert Wigley Aug 27 '14 at 09:17
  • Do you know if it's possible to change the label on the buttons from Cancel to Silent? – Robert Wigley Aug 27 '14 at 09:18
  • 1
    Behind the `SuppressibleMsgBox` (and `MsgBox`) functions is the [`MessageBox`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx) Windows API function which builds the dialog. And that function gets button captions from the currently selected language and provides no way to use custom captions. But yes, I think [`it should be possible`](http://www.codeguru.com/cpp/w-p/win32/messagebox/article.php/c10873/MessageBox-with-Custom-Button-Captions.htm), but you'd need to have an external library with a hook. It would be easier to make a custom form for this. – TLama Aug 27 '14 at 09:37
  • Thanks. However, I have actually now found a more elegant solution for what I was trying to achieve, in that even when you need a third outcome, which I want to be the default option when the /verysilent switch is used from the commandline, you actually don't need to display a third button. You can still have a MB_YESNO, but give it a different default value e.g. IDIGNORE and call that when running silently. – Robert Wigley Aug 27 '14 at 10:54
1

Here is the final code in case it is useful for anyone else:

var
  intMsgBoxResult: Integer;
if ((strExistingInstallPath <> '') and (strExistingVersion = '2.5.3')) then
begin
  intMsgBoxResult := SuppressibleMsgBox('Setup has detected that ' + strMyAppName + ' ' + strExistingVersion + '.' + strExistingBuild + ' is installed.' + #13#10 + #13#10 +
    'The existing version must be removed before installing or upgrading to ' + strMyAppVersion + '.' + strMyAppBuild + '.' + #13#10 + #13#10 +
    'Would you like Setup to uninstall the existing version?',
    mbConfirmation, MB_YESNO, IDIGNORE);
  if intMsgBoxResult = IDYES then
    begin
      Exec(GetUninstallString, '/silent', '', SW_SHOW,
        ewWaitUntilTerminated, intResultCode);
      Result := True;
    end;
  if intMsgBoxResult = IDNO then 
    begin
      MsgBox('The existing version must be removed first.' + #13#10 +
        'Setup is unable to continue. Setup will now exit.',
        mbError, MB_OK);
      Result := False;
    end;
  if intMsgBoxResult = IDIGNORE then
    begin
      Exec(GetUninstallString, '', '', SW_SHOW,
        ewWaitUntilTerminated, intResultCode);
      Result := True;
    end; 
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Robert Wigley
  • 1,917
  • 22
  • 42
  • 2
    Case is better here. But anyway, now you are testing the `intMsgBoxResult` value always for 3 times. If you really want to use `if`, then add at least `else` (as I've shown) because if the `intMsgBoxResult` value will be `IDYES`, there is no need to test is also for `IDNO` and `IDIGNORE`. – TLama Aug 27 '14 at 11:02
  • 1
    Good point. Will make the amendments and might switch to using case instead if you think it is a better way of handling it. Really grateful for the help and advice. – Robert Wigley Aug 27 '14 at 18:43