Search code examples
inno-setupprogress

How to show progress during "PrepareToInstall"?


An installer I'm working on does most of its work in the PrepareToInstall function, as everything I need to do might fail, and therefore this is the appropriate place to handle these things in case they do fail. Any failure can be automatically reported by passing the error message in the function's result. There are only 3 small files which the installer actually copies over.

The problem is that the wizard seems to freeze (or not respond rather) during this function, just showing a blank page titled "Preparing to install..." while in reality, it's going through my install process.

I would like to show the progress to the user with a simple procedure ShowProgress(const S: String); which shows the user what it's actually doing. How can I do this?

This is how I'm doing my install, where I'd like to wrap each call to Log()...

function PrepareToInstall(var NeedsRestart: Boolean): String;
var
  R: Integer;
begin
  Result:= '';
  try
    Log('Doing this...');
    R:= DoThis;
    case R of
      0: begin
        Result:= '';
      end;
      1: begin
        Result:= 'Error message 1 was raised while doing this.';
      end;
      else begin
        Result:= 'Unexpected error doing this: ' + IntToStr(R);
      end;
    end;

    if Result = '' then begin
      Log ('Doing that...');
      R:= DoThat;
      case R of
        0: begin
          Result:= '';
        end;
        1: begin
          Result:= 'Error message 1 was raised while doing that.';
        end;
        else begin
          Result:= 'Unexpected error doing that: ' + IntToStr(R);
        end;
      end;
    end;

    if Result = '' then begin
      Log ('Doing something else...');
      R:= DoSomethingElse;
      case R of
        0: begin
          Result:= '';
        end;
        1: begin
          Result:= 'Error message 1 was raised while doing something else.';
        end;
        else begin
          Result:= 'Unexpected error doing something else: ' + IntToStr(R);
        end;
      end;
    end;

    //A few more blocks like above

    //Error logging
    if Result <> '' then begin
      Log('FAILURE: '+Result);
    end;

  except
    Result:= 'EXCEPTION';
    Log('EXCEPTION');
  end;
end;

Solution

  • The code written in the PrepareToInstall function blocks the Windows message pump from processing, rendering the wizard form non-responsive. If many controls are needed to be visible in this screen, showing perhaps a progress bar and list of steps to take, this can be done with a form inside of a DLL. Make sure there is a thread in this DLL which does the actual install process, and only update the GUI to display the status to the user. This DLL form may overlay the wizard, or may even be embedded inside of the wizard in a custom wizard page, for example. The idea is to move your install code from the PrepareToInstall function to within this thread, and only then will you be able to achieve a fully responsive GUI during this process. From the PrepareToInstall function, there should be just one DLL call to initiate the install process, which in turn shows the form from the DLL.

    The result may look something like this (in the works):

    enter image description here