Search code examples
checkboxinno-setuprestartpascalscript

How to restart Inno Setup installer based on result of procedure that executes a program/subinstaller


I have an install procedure that is executed if the sub exe is not installed, and if so, I want the final "lauch my app" checkbox at the end to be replaced by a "restart computer" checkbox.

How can I do that?

I tried to use the NeedRestart() and also use a global boolean variable. But I can't seem to make it work.

Minimal reproductible example:

the file line :

[Files] 
Source: "Dependencies\ndp48-x86-x64-allos-enu.exe"; \
    DestDir: "{app}"; Flags: deleteafterinstall; \
    AfterInstall: InstallNETFramework; Check: NETFrameworkIsNotInstalled

The installation procedure:

procedure InstallNETFramework;
var
  ResultCode: Integer;
  StatusText: string;
begin
  StatusText := WizardForm.StatusLabel.Caption;
  WizardForm.StatusLabel.Caption := 'Installing .NET Framework 4.8...';
  WizardForm.ProgressGauge.Style := npbstMarquee;
  try
    if not ShellExec('open', ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'), '/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) 
    then
    begin
      MsgBox('.NET Framework 4.8 Installation did not succeed : ' + IntToStr(ResultCode) + '.', mbError, MB_OK);
    end;
  finally
    WizardForm.StatusLabel.Caption := StatusText;
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;

The NeedToRestart event function:

[Code]
var NeedToRestart: boolean;

function NeedToRestart();
begin
//??
end;

If this installation procedure is executed, then at the end, instead of having a "launch {{app}}" I want "restart computer". If possible with the option now or later? It's fine if not.


Solution

  • As you correctly assumed:

    • introduce a global Boolean variable
    • set it when the .NET installer is successfully executed (you should check ResultCode to be really sure that it did)
    • and use the variable in the NeedRestart event function:
    var
      RestartNeeded: Boolean;
    
    function NeedRestart(): Boolean;
    begin
      Result := RestartNeeded;
    end;
    
    procedure InstallNETFramework;
    var
      ResultCode: Integer;
    begin
      // ...
      if Exec(ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'),
              '/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) and
         (ResultCode = { whatever success exit code[s] the installer uses }) then
      begin
        Log('.NET Framework 4.8 installation succeeded, need restart');
        RestartNeeded := True;
        // Or if the installer has specific code to indicate success with restart:
        // RestartNeeded := (ResultCode = RestartCode);
      end
        else
      begin
        MsgBox('.NET Framework 4.8 installation did not succeed: ' +
                 IntToStr(ResultCode) + '.', mbError, MB_OK);
      end;
      // ...
    end;
    

    .NET installer return codes seem to be documented here (but I didn't test it):
    https://learn.microsoft.com/en-us/dotnet/framework/deployment/deployment-guide-for-developers#return-codes


    Similar question: Inno Setup and VC Redistributable and handling exit code 3010 gracefully


    As hinted by @PMF in your other question, as alternative approach might be to try the RestartIfNeededByRun directive along with running your subinstaller using [Run]. Though that limits error handling.

    If you want to keep executing (and checking) the .NET installation in code, you can use MakePendingFileRenameOperationsChecksum function:

    var
      ResultCode: Integer;
      Checksum: string;
    
      // ...
      Checksum := MakePendingFileRenameOperationsChecksum;
      if Exec(ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'),
              '/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) and
         (ResultCode = { whatever success exit code[s] the installer uses }) then
      begin
        Log('.NET Framework 4.8 installation succeeded, need restart');
        if Checksum <> MakePendingFileRenameOperationsChecksum then
        begin
          Log('Need to restart detected');
          RestartNeeded := True;
        end;
      end
      // ...