Display the info about wrong hash of downloaded file in a nice task dialog window in Inno Setup

207 Views Asked by At

I originally asked about this question on another platform (here).

In Inno Setup it has the following message definition:

ErrorFileHash2=Invalid file hash: expected %1, found %2

This message is displayed when the installer tries to download and run a file with the wrong hash value.

In my script I have:

function NextButtonClick(CurPageID: integer): boolean;
begin
    Result := True;
 
  if (CurPageID = wpSelectTasks) then
  begin
    DownloadPage.Clear;
    if (WizardIsTaskSelected('downloadhelp')) then
      AddFileForDownload('{#HelpDocSetupURL}', 'HelpDocSetup.exe', 
        '{#GetSHA256OfFile("..\HelpNDoc\CHM\Output\MSAHelpDocumentationSetup.exe")}');
  end
    else
  if (CurPageID = wpReady) then
  begin
    DownloadPage.Show;
    try
      try
        DownloadPage.Download;
        Result := True;
      except
        SuppressibleMsgBox(
          AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
        Result := False;
      end;
    finally
      DownloadPage.Hide;
    end;
  end;
end;

The error message that is displayed when there is an issue is rather ugly. The following was suggested to me:

It only shows a message box if you don't handle the exception. Use try/except and then you can do things like re-raising the exception with a filename added or using a task dialog.

I thought I would try the message box designer:

enter image description here

Which creates the following code:

// Display a message box
SuppressibleTaskDialogMsgBox(
  'Unable to download [file]', 'This is because the checksum value does not match',
  mbError, MB_OK, ['OK'], 0, IDOK);

But I don't know what I am doing here.

  • How do I handle the exception that displays this error?
  • How do I show a better task dialog? Once that also includes the has details and file name?
1

There are 1 best solutions below

0
On BEST ANSWER

Just replace your current:

SuppressibleMsgBox(
  AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);

With your new code:

SuppressibleTaskDialogMsgBox(
  'Unable to download [file]', 'This is because the checksum value does not match',
  mbError, MB_OK, ['OK'], 0, IDOK);

enter image description here


If you want to identify the failed download, you can use the value of the DownloadPage.Msg2Label.Caption (you can see it if, you move the message box).

If you need to include the hashes in your message, you would have to parse the data from the error message. That's bit fragile approach. But if you provide a fallback message, in case the parsing fails, it's doable.

The following function tries to parse the data out of any standard Inno Setup string:

function ParseDataFromSetupMessage(
  Msg: string; ID: TSetupMessageID; var Data: TArrayOfString): Boolean;
var
  MsgOrig, Pattern, PatternOrig, S: string;
  I, P, P2: Integer;
begin
  try
    MsgOrig := Msg;
    Pattern := SetupMessage(ID);
    PatternOrig := Pattern;
    while (Msg <> '') and (Pattern <> '') do
    begin
      P := Pos('%', Pattern);
      if (P = 0) or (P = Length(Pattern)) or (P > 1) then
      begin
        if (P = 0) or (P = Length(Pattern)) then P := Length(Pattern) + 1;

        if Copy(Msg, 1, P - 1) <> Copy(Pattern, 1, P - 1) then Abort;

        Delete(Msg, 1, P - 1);
        Delete(Pattern, 1, P - 1);
      end
        else
      if (Pattern[2] < '1') or (Pattern[2] > '9') then
      begin
        if Copy(Msg, 1, 1) <> '%' then Abort;
        Delete(Pattern, 1, 1);
        Delete(Msg, 1, 1);
      end
        else
      begin
        I := StrToInt(Pattern[2]);
        Delete(Pattern, 1, 2);
        if Length(Pattern) = 0 then
        begin
          S := Msg;
          SetLength(Msg, 0);
        end
          else
        begin
          P := Pos('%', Pattern);
          if P = 0 then P := Length(Pattern) + 1;
          P2 := Pos(Copy(Pattern, 1, P - 1), Msg);
          if P2 = 0 then Abort;
          S := Copy(Msg, 1, P2 - 1);
          Delete(Msg, 1, P2 - 1);
        end;

        if GetArrayLength(Data) < I then
          SetArrayLength(Data, I);
        Data[I - 1] := S;
      end;
    end;

    if Msg <> Pattern then Abort;

    Result := True;
  except
    Log(Format('"%s" does not seem to match format string "%s".', [
      MsgOrig, PatternOrig]));
    Result := False;
  end;
end;

You can use both in your except block like this:

except
  Msg := GetExceptionMessage;
  if ParseDataFromSetupMessage(Msg, msgErrorFileHash2, Data) then
  begin
    Expected := Data[0];
    Hash := Data[1];
    Msg :=
      'This is because the checksum value does not match.' + #13+
      'Download: ' + DownloadPage.Msg2Label.Caption + #13 +
      'Expected: ' + Expected + #13 +
      'Got: ' + Hash;
  end
    else
  begin
    // Failed for other reasons?
    Msg :=
      'Download has failed.' + #13+
      'Download: ' + DownloadPage.Msg2Label.Caption + #13 +
      'Details: ' + Msg;
  end;
  SuppressibleTaskDialogMsgBox(
    'Unable to download', Msg, mbError, MB_OK, ['OK'], 0, IDOK);
  Result := False;
end;