Search code examples
windowsinstallationprogress-barinno-setuppascalscript

Copy Files with progress bar on a custom page of Inno Setup


I'm currently working on a program that updates our company's software.

I'm letting a User chose the location of the installed program and a backup location in an CreateInputDirPage.

Currently I'm creating a mask for the selection of the two directorys:

SelectPathPage := CreateInputDirPage(PreviousPageId,
  'Text 1',
  'Text 2.',
  'Text 3', False, 'New Folder');
  SelectPathPage.Add('Path to company program');
  SelectPathPage.Add('Path to backup folder');

Then I'm validating with existing files if the first folder indeed holds our company's program. Now I want to copy the first selection to a new subfolder in the backup folder.

I found this sample code from another question for copying the files:

DirectoryCopy(SelectPathPage.Values[0], SelectPathPage.Values[1]);

Which seems to work with the NextButtonClick function.

How can I copy the folder and the content of the folder on a separate mask after the SelectPathPage mask with a progress bar and making the next button available when the copy is finished. It should be similar to the "Install" mask with the progress bar. Is it even possible to create something like this in a custom mask in Inno Setup?

Thanks in Advance


Solution

  • Use CreateOutputProgressPage to create the progress page.

    And modify the DirectoryCopy function from Copying hidden files in Inno Setup to advance the progress on the page.

    To calculate the total size (to set the maximum of the progress bar), the code needs GetDirSize function from Inno Setup get directory size including subdirectories.

    [Code]
    
    const
      ProgressRatio = 1024;
    
    procedure DirectoryCopyWithProgress(
      SourcePath, DestPath: string; ProgressPage: TOutputProgressWizardPage);
    var
      FindRec: TFindRec;
      SourceFilePath: string;
      DestFilePath: string;
      Size: Int64;
    begin
      if FindFirst(SourcePath + '\*', FindRec) then
      begin
        try
          repeat
            if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
            begin
              SourceFilePath := SourcePath + '\' + FindRec.Name;
              DestFilePath := DestPath + '\' + FindRec.Name;
              ProgressPage.SetText(SourceFilePath, DestFilePath);
              if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
              begin
                Size := Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow;
                if FileCopy(SourceFilePath, DestFilePath, False) then
                begin
                  Log(Format('Copied %s to %s with %s bytes', [
                    SourceFilePath, DestFilePath, IntToStr(Size)]));
                end
                  else
                begin
                  Log(Format('Failed to copy %s to %s', [
                    SourceFilePath, DestFilePath]));
                end;
              end
                else
              begin
                Size := 0;
                if DirExists(DestFilePath) or CreateDir(DestFilePath) then
                begin
                  Log(Format('Created %s', [DestFilePath]));
                  DirectoryCopyWithProgress(
                    SourceFilePath, DestFilePath, ProgressPage);
                end
                  else
                begin
                  Log(Format('Failed to create %s', [DestFilePath]));
                end;
              end;
    
              Size := Size / ProgressRatio;
              ProgressPage.SetProgress(
                ProgressPage.ProgressBar.Position + Longint(Size),
                ProgressPage.ProgressBar.Max);
            end;
          until not FindNext(FindRec);
        finally
          FindClose(FindRec);
        end;
      end
        else
      begin
        Log(Format('Failed to list %s', [SourcePath]));
      end;
    end;
    
    function SelectPathPageNextButtonClick(Sender: TWizardPage): Boolean;
    var
      SourcePath: string;
      DestPath: string;
      ProgressPage: TOutputProgressWizardPage;
      TotalSize: Longint;
    begin
      ProgressPage := CreateOutputProgressPage('Copying files...', '');
      SourcePath := TInputDirWizardPage(Sender).Values[0];
      DestPath := TInputDirWizardPage(Sender).Values[1];
      TotalSize := GetDirSize(SourcePath) / ProgressRatio;
      Log(Format('Total size is %s', [IntToStr(TotalSize)]));
      ProgressPage.SetProgress(0, TotalSize);
      ProgressPage.Show;
      try
        DirectoryCopyWithProgress(SourcePath, DestPath, ProgressPage);
      finally
        ProgressPage.Hide;
        ProgressPage.Free;
      end;
      Result := True;
    end;
    
    procedure InitializeWizard();
    var
      SelectPathPage: TInputDirWizardPage;
    begin
      SelectPathPage :=
        CreateInputDirPage(
          wpSelectDir, 'Text 1', 'Text 2.', 'Text 3', False, 'New Folder');
      SelectPathPage.Add('Path to company program');
      SelectPathPage.Add('Path to backup folder');
      SelectPathPage.OnNextButtonClick := @SelectPathPageNextButtonClick;
    end;
    

    enter image description here

    enter image description here