Goozak
Goozak

Reputation: 529

Detect if restart is pending before installing in Inno Setup

Is there a way to prevent installation if a reboot/restart is already pending/required?

Our setup installs SQL Server Express and it will sometimes refuse to do so if there is a pending restart in the system. Can Inno Setup detect this condition so I can tell the user to reboot before installing our software?

I know about MakePendingFileRenameOperationsChecksum but it's usually mentioned to detect whether the reboot required condition appeared DURING the setup. Can it be used BEFORE?

Upvotes: 3

Views: 1385

Answers (2)

Martin Prikryl
Martin Prikryl

Reputation: 202118

If you want to detect, if there is a pending rename that requires a restart, query PendingFileRenameOperations registry value.

See also How to find out if an MSI I just installed requested a Windows reboot?

function IsRestartPending: Boolean;
var
  S: string;
begin
  if RegQueryMultiStringValue(
       HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager',
       'PendingFileRenameOperations', S) then
  begin
    Log(Format('PendingFileRenameOperations value exists with value [%s]', [S]));
    Result := (Trim(S) <> ''); { This additional check is probably not needed }
  end
    else
  begin
    Log('PendingFileRenameOperations value does not exist');
    Result := False;
  end;
end;

function InitializeSetup(): Boolean;
begin
  if IsRestartPending then
  begin
    MsgBox('Restart your machine please', mbError, MB_OK);
    Result := False;
    Exit;
  end;

  Result := True;
end;

If you need to test for other actions that may need restart, you will have to adapt the answer by @Jerry for Inno Setup.

Upvotes: 1

Jerry Dodge
Jerry Dodge

Reputation: 27266

The other accepted answer only covered one scenario. However, there are actually numerous different scenarios to check. I found this article describing all the different registry things to check, and wrote a function around it. This is actually in Delphi, but should be easily implemented in Inno Setup as well. In fact, part of it I got from here, which was in Inno Setup, for checking valid GUID.

Please note that this generally checks for pending Windows updates, which may not necessarily be desired. You can modify it and remove those checks you don't wish to perform for your purpose. The second and third checks for PendingFileRenameOperations actually appear not necessary for SQL Server.

const
  S_OK = $00000000;
  CO_E_CLASSSTRING = $800401F3;

type
  LPCLSID = TGUID;
  LPCOLESTR = WideString;

function CLSIDFromString(lpsz: LPCOLESTR; pclsid: LPCLSID): HRESULT;
  stdcall; external 'ole32.dll';

function IsValidGuid(const Value: string): Boolean;
var
  GUID: LPCLSID;
  RetVal: HRESULT;
begin
  RetVal := CLSIDFromString(LPCOLESTR(Value), GUID);
  Result := RetVal = S_OK;
  if not Result and (RetVal <> CO_E_CLASSSTRING) then
    OleCheck(RetVal);
end;

function IsRestartPending(const RestartOnly: Boolean = True): Boolean;
var
  R: TRegistry;
  L: TStringList;
  X: Integer;
  T: String;
begin
  R:= TRegistry.Create(KEY_READ);
  try
    L:= TStringList.Create;
    try
      Result:= False;
      R.RootKey:= HKEY_LOCAL_MACHINE;

      if R.OpenKey('SOFTWARE\Microsoft\Updates', False) then begin
        try
          if R.ValueExists('UpdateExeVolatile') then begin
            if R.ReadInteger('UpdateExeVolatile') <> 0 then
              Result:= True;
          end;
        finally
          R.CloseKey;
        end;
      end;


      if not RestartOnly then begin
        //These next 2 checks are not necessary for a SQL Server installation.
        if not Result then begin
          if R.OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager', False) then begin
            try
              Result:= R.ValueExists('PendingFileRenameOperations');
            finally
              R.CloseKey;
            end;
          end;
        end;


        if not Result then begin
          if R.OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager', False) then begin
            try
              Result:= R.ValueExists('PendingFileRenameOperations2');
            finally
              R.CloseKey;
            end;
          end;
        end;
      end;

      if not Result then begin
        Result:= R.KeyExists('SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired');
      end;



      if not Result then begin
        if R.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending', False) then begin
          try
            L.Clear;
            R.GetKeyNames(L);
            for X := 0 to L.Count-1 do begin
              if IsValidGuid(L[X]) then begin
                Result:= True;
                Break;
              end;
            end;
          finally
            R.CloseKey;
          end;
        end;
      end;



      if not Result then begin
        Result:= R.KeyExists('SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting');
      end;


      if not Result then begin
        if R.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', False) then begin
          try
            Result:= R.ValueExists('DVDRebootSignal');
          finally
            R.CloseKey;
          end;
        end;
      end;


      if not Result then begin
        Result:= R.KeyExists('Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending');
      end;


      if not Result then begin
        Result:= R.KeyExists('Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress');
      end;



      if not Result then begin
        Result:= R.KeyExists('Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending');
      end;



      if not Result then begin
        Result:= R.KeyExists('SOFTWARE\Microsoft\ServerManager\CurrentRebootAttempts');
      end;


      if not Result then begin
        if R.OpenKey('SYSTEM\CurrentControlSet\Services\Netlogon', False) then begin
          try
            Result:= R.ValueExists('JoinDomain');
          finally
            R.CloseKey;
          end;
        end;
      end;


      if not Result then begin
        if R.OpenKey('SYSTEM\CurrentControlSet\Services\Netlogon', False) then begin
          try
            Result:= R.ValueExists('AvoidSpnSet');
          finally
            R.CloseKey;
          end;
        end;
      end;


      if not Result then begin
        if R.OpenKey('SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName', False) then begin
          try
            T:= R.ReadString('ComputerName');
          finally
            R.CloseKey;
          end;
        end;


        if R.OpenKey('SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName', False) then begin
          try
            if R.ReadString('ComputerName') <> T then
              Result:= True;
          finally
            R.CloseKey;
          end;
        end;
      end;


    finally
      L.Free;
    end;
  finally
    R.Free;
  end;
end;

Upvotes: 0

Related Questions