[Run]
我的 Inno Setup 脚本部分中有一些命令。现在,如果它们中的任何一个返回失败代码(非零返回值),则设置将继续,而不会向用户发出任何警告。期望的行为是设置失败并回滚。
如何启用此功能?我找不到任何Run
会强制执行此行为的条目的标志。我错过了什么吗?
[Run]
我的 Inno Setup 脚本部分中有一些命令。现在,如果它们中的任何一个返回失败代码(非零返回值),则设置将继续,而不会向用户发出任何警告。期望的行为是设置失败并回滚。
如何启用此功能?我找不到任何Run
会强制执行此行为的条目的标志。我错过了什么吗?
就我而言,您必须为此使用部分,使用函数[Code]
运行文件,返回时检查并运行您的卸载脚本。Exec
ResultCode
我是这样做的:
{tmp}\install.error
使用 Inno Setup 的BeforeInstall
参数和SaveStringToUTF8File
过程将错误消息(中止确认消息或只是通知消息)写入临时文件。您可以使用 Inno Setup 的常量,例如{cm:YourCustomMessage}
.
使用 Windows 命令外壳cmd.exe /s /c
运行所需的程序。还可以通过- https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx使用条件执行del
命令。因此,如果命令成功(退出代码 0),错误消息文件将被删除。请注意. 使用下面的代码作为示例。&&
cmd.exe /s /c
根据错误严重程度,{tmp}\install.error
使用 Inno Setup 的AfterInstall
参数ConfirmInstallAbortOnError
或过程检查错误消息文件的存在。NotifyInstallAbortOnError
他们将通过适当的通知或确认(以及可选的日志文件显示)中止安装并使用执行回滚Exec(ExpandConstant('{uninstallexe}'), ...
ShouldAbortInstallation
全局变量用于保持状态。Inno Setup 的ShouldSkipPage(PageID: Integer)
功能用于隐藏最后一页。部分中的所有命令[Run]
都应使用Check
带CheckInstallationIsNotAborted
函数的参数。它将在某些时候阻止它们在失败后执行。
请参见下面的示例。希望这可以帮助。
[CustomMessages]
InstallAbortOnErrorConfirmationMessage=An error has occurred during setup.%nAbort installation?
InstallAbortOnErrorNotificationMessage=An error has occurred during setup.%nInstallation will be aborted.
RunProgram1ErrorMsg=Post installation phase 1 failed. Should abort install?
RunProgram2ErrorMsg=Post installation phase 2 failed. Installation will be aborted. Please, contact tech support.
RunProgram1StatusMsg=Post installation phase 1 is in progress
RunProgram2StatusMsg=Post installation phase 2 is in progress
[Run]
; Write error text to file. Delete file on succeed. Abort installation if file exists after command execution.
Filename: "cmd.exe"; Parameters: "/s /c "" ""{app}\program1.exe"" /param1 /param2:""val2"" && del /F /Q ""{tmp}\install.error"" """; \
WorkingDir:"{app}"; Flags: runhidden; \
BeforeInstall: SaveStringToUTF8File('{tmp}\install.error', '{cm:RunProgram1ErrorMsg}', False); \
AfterInstall: ConfirmInstallAbortOnError('{tmp}\install.error', '{app}\logs\setup.log'); \
StatusMsg: "{cm:RunProgram1StatusMsg}"; \
Check: CheckInstallationIsNotAborted;
Filename: "cmd.exe"; Parameters: "/s /c "" ""{app}\program2.exe"" && del /F /Q ""{tmp}\install.error"" """; \
WorkingDir:"{app}"; Flags: runhidden; \
BeforeInstall: SaveStringToUTF8File('{tmp}\install.error', '{cm:RunProgram2ErrorMsg}', False); \
AfterInstall: NotifyInstallAbortOnError('{tmp}\install.error', '{app}\logs\setup.log'); \
StatusMsg: "{cm:RunProgram2StatusMsg}"; \
Check: CheckInstallationIsNotAborted;
[Code]
var
ShouldAbortInstallation: Boolean;
procedure SaveStringToUTF8File(const FileName, Content: String; const Append: Boolean);
var
Text: array [1..1] of String;
begin
Text[1] := Content;
SaveStringsToUTF8File(ExpandConstant(FileName), Text, Append);
end;
function LoadAndConcatStringsFromFile(const FileName: String): String;
var
Strings: TArrayOfString;
i: Integer;
begin
LoadStringsFromFile(FileName, Strings);
Result := '';
if High(Strings) >= Low(Strings) then
Result := Strings[Low(Strings)];
for i := Low(Strings) + 1 to High(Strings) do
if Length(Strings[i]) > 0 then
Result := Result + #13#10 + Strings[i];
end;
procedure ConfirmInstallAbortOnError(ErrorMessageFile, LogFileToShow: String);
var
ErrorCode: Integer;
ErrorMessage: String;
begin
ErrorMessageFile := ExpandConstant(ErrorMessageFile);
LogFileToShow := ExpandConstant(LogFileToShow);
Log('ConfirmInstallAbortOnError is examining file: ' + ErrorMessageFile);
if FileExists(ErrorMessageFile) then
begin
Log('ConfirmInstallAbortOnError: error file exists');
{ Show log file to the user }
if Length(LogFileToShow) > 0 then
ShellExec('', LogFileToShow, '', '', SW_SHOW, ewNoWait, ErrorCode);
ErrorMessage := LoadAndConcatStringsFromFile(ErrorMessageFile);
if Length(ErrorMessage) = 0 then
ErrorMessage := '{cm:InstallAbortOnErrorConfirmationMessage}';
if MsgBox(ExpandConstant(ErrorMessage), mbConfirmation, MB_YESNO) = IDYES then
begin
Log('ConfirmInstallAbortOnError: should abort');
ShouldAbortInstallation := True;
WizardForm.Hide;
MainForm.Hide;
Exec(ExpandConstant('{uninstallexe}'), '/SILENT', '', SW_HIDE,
ewWaitUntilTerminated, ErrorCode);
MainForm.Close;
end;
end;
Log('ConfirmInstallAbortOnError finish');
end;
procedure NotifyInstallAbortOnError(ErrorMessageFile, LogFileToShow: String);
var
ErrorCode: Integer;
ErrorMessage: String;
begin
ErrorMessageFile := ExpandConstant(ErrorMessageFile);
LogFileToShow := ExpandConstant(LogFileToShow);
Log('NotifyInstallAbortOnError is examining file: ' + ErrorMessageFile);
if FileExists(ErrorMessageFile) then
begin
Log('NotifyInstallAbortOnError: error file exists');
{ Show log file to the user }
if Length(LogFileToShow) > 0 then
ShellExec('', LogFileToShow, '', '', SW_SHOW, ewNoWait, ErrorCode);
ErrorMessage := LoadAndConcatStringsFromFile(ErrorMessageFile);
if Length(ErrorMessage) = 0 then
ErrorMessage := '{cm:InstallAbortOnErrorNotificationMessage}';
MsgBox(ExpandConstant(ErrorMessage), mbError, MB_OK);
Log('NotifyInstallAbortOnError: should abort');
ShouldAbortInstallation := True;
WizardForm.Hide;
MainForm.Hide;
Exec(ExpandConstant('{uninstallexe}'), '/SILENT', '', SW_HIDE,
ewWaitUntilTerminated, ErrorCode);
MainForm.Close;
end;
Log('NotifyInstallAbortOnError finish');
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := ShouldAbortInstallation;
end;
function CheckInstallationIsNotAborted(): Boolean;
begin
Result := not ShouldAbortInstallation;
end;
该[Run]
部分在安装完成后发生,因此此时无法回滚,因为它已经完成。
但是,您可以做的是在您或执行您的方法所需的任何内容之后使用该部分中的AfterInstall 。这会在完成安装之前运行,因此此时取消会执行删除所有文件的回滚。[Files]
.exe
如果将其与此答案中的“CancelWithoutPrompt”结合使用,则可以在以交互模式运行时进行回滚。不幸的是,静音模式似乎没有回滚。
[Files]
Source: src\myapp.exe; DestDir: "{app}"; AfterInstall: RunMyAppCheck
[Code]
var CancelWithoutPrompt: boolean;
function InitializeSetup(): Boolean;
begin
CancelWithoutPrompt := false;
result := true;
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
if CancelWithoutPrompt then
Confirm := false; { hide confirmation prompt }
end;
procedure RunMyAppCheck();
var
resultCode: int;
begin
Exec(ExpandConstant('{app}\myapp.exe'), '--verify --example-other-params',
'', SW_HIDE, ewWaitUntilTerminated, resultCode);
if resultCode <> 0 then
begin
SuppressibleMsgBox(
'MyApp failed, exit code ' + IntToStr(resultCode) + '. Aborting installation.',
mbCriticalError, MB_OK, 0);
CancelWithoutPrompt := true;
WizardForm.Close;
end;
end;