13

[Run]InnoSetupスクリプトのセクションにいくつかのコマンドがあります。現在、それらのいずれかが失敗コード(ゼロ以外の戻り値)を返した場合、セットアップはユーザーに警告することなく続行されます。望ましい動作は、セットアップが失敗してロールバックすることです。

これを有効にするにはどうすればよいですか?Runこの動作を強制するエントリのフラグが見つかりませんでした。私は何かが足りないのですか?

4

4 に答える 4

11

私に関する限り、そのため[Code]のセクションを使用し、関数を使用してファイルを実行し、戻ったときExecにチェックResultCodeして、アンインストールスクリプトを実行する必要があります。

于 2009-07-13T23:59:19.683 に答える
7

私はそれをこのようにしました:

  1. {tmp}\install.errorInno SetupのBeforeInstallパラメータwithSaveStringToUTF8Fileプロシージャを使用して、エラーメッセージ(中止確認メッセージまたは通知メッセージのみ)を一時ファイルに書き込みます。などのInnoSetupの定数を使用できます{cm:YourCustomMessage}

  2. Windowsコマンドシェルcmd.exe /s /cを使用して、目的のプログラムを実行します。delまた、コマンドの条件付き実行を-https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspxで使用&&ます。したがって、コマンドが成功した場合(終了コード0)、エラーメッセージファイルは削除されます。での特別な引用符の処理に注意してくださいcmd.exe /s /c。以下のコードを例として使用してください。

  3. エラーの重大度に応じて、またはプロシージャのいずれかで{tmp}\install.errorInnoSetupのAfterInstallパラメータを使用してエラーメッセージファイルの存在を確認します。適切な通知または確認(およびオプションでログファイルの提示)を使用してインストールを中止し、を使用してロールバックを実行しますConfirmInstallAbortOnErrorNotifyInstallAbortOnErrorExec(ExpandConstant('{uninstallexe}'), ...

  4. 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;
于 2014-06-20T08:35:03.420 に答える
2

この[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;
于 2020-09-17T20:30:24.680 に答える
0

AfterInstallセクションのフラグを使用してRun、プログラムの実行をトリガーし、結果コードをキャッチできます。

ここで私の答えを参照してください。

次に、結果コードに従って、インストールをキャンセルできます。

于 2015-07-15T09:59:21.917 に答える