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:
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.
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);
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;