Hopefully the title is clear enough already, but to explain better: I have a large selection of options in the Select Components
page (about 1.4 GB of .png files) and my goal is to lighten the compile size for the installer by having it download files to {tmp}
and installed after they've been unzipped. Unfortunately, I've ran into a problem while trying to follow answers from other questions:
All files are downloaded regardless of what components the user selected, leading to large amounts of time spent extracting, which also unfortunately has no progress bar to give feedback to the user.
Currently all [Code]
for my installer (sorry, it's lengthy)
[Files]
// Test
Source: "{tmp}\packs\Sapphic_icons\Dead by Daylight\DeadByDaylight\Content\UI\Icons\README.txt"; DestDir: "{app}"; Components: sapphic; Flags: ignoreversion recursesubdirs createallsubdirs external; Check: ExtractedFileNeedsInstallation
[Types]
Name: "sapphic"; Description: "Sapphic Pack";
Name: "custom"; Description: "Customized"; Flags: iscustom;
[Components]
Name: "sapphic"; Description: "Sapphic Pack - WIP*"; Types: custom sapphic;
[Code]
{ —————————— Extraction Logging ———————————————————————————————————————— }
const
NO_PROGRESS_BOX = 4;
RESPOND_YES_TO_ALL = 16;
procedure UnZip(ZipPath, FileName, TargetPath: string);
var
Shell: Variant;
ZipFile: Variant;
Item: Variant;
TargetFolder: Variant;
begin
Shell := CreateOleObject('Shell.Application');
ZipFile := Shell.NameSpace(ZipPath);
if VarIsClear(ZipFile) then
RaiseException(Format('Cannot open ZIP file "%s" or does not exist', [ZipPath]));
Item := ZipFile.ParseName(FileName);
if VarIsClear(Item) then
RaiseException(Format('Cannot find "%s" in "%s" ZIP file', [FileName, ZipPath]));
TargetFolder := Shell.NameSpace(TargetPath);
if VarIsClear(TargetFolder) then
RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Extraction Handling ———————————————————————————————————————— }
function ExtractedFileNeedsInstallation: Boolean;
var
TargetPath: String;
begin
TargetPath := ExpandConstant('{userappdata}')+'\App\packs';
Result := not FileExists(TargetPath);
Log(Format('ExtractedFileNeedsInstallation: %d', [Result]));
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Download Progress ———————————————————————————————————————— }
var
DownloadPage: TDownloadWizardPage;
function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean;
begin
if Progress = ProgressMax then
Log(Format('Successfully downloaded file to {tmp}: %s', [FileName]));
Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Setup Wizard ———————————————————————————————————————— }
procedure InitializeWizard();
begin
{ Download Page }
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), @OnDownloadProgress);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Download Handling ———————————————————————————————————————— }
function NextButtonClick(CurPageID: Integer): Boolean;
var
Temp: String;
begin
if CurPageID = wpReady then begin
if (not ExtractedFileNeedsInstallation) then
begin
Result := True;
end
else
begin
DownloadPage.Clear;
DownloadPage.Add('https://www.dropbox.com/scl/fi/fautmpacdsl22h6y41jrv/packs.zip?rlkey=ul3kl1f9o3258yguitprisx6c&st=wwry4esv&dl=1', 'packs.zip', '');
DownloadPage.Show;
try
try
DownloadPage.Download;
Temp := ExpandConstant('{tmp}');
UnZip(Temp+'\packs.zip', 'packs', Temp);
Result := True;
except
SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
Result := False;
end;
finally
DownloadPage.Hide;
end;
end;
end else
Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
Your code includes only single ZIP file download and single component. What does not really correspond to your claims.
Anyway, if you want to download only subset of files for each of your supposed components, you need to split your downloads to separate component packages in the first place. That's not even Inno Setup question.
Then you can tell Inno Setup to download only the packages you need, by querying selected components using WizardIsComponentSelected
and adding corresponding download URL.
Like:
if WizardIsComponentSelected('component1') then
DownloadPage.Add('https://example.com/component1.zip', 'component1.zip', '');
if WizardIsComponentSelected('component2') then
DownloadPage.Add('https://example.com/component2.zip', 'component2.zip', '');
// ...
Similarly, you then need to UnZip
each selected/downloaded package separately:
if WizardIsComponentSelected('component1') then
UnZip(Temp+'\component1.zip', 'packs', Temp);
if WizardIsComponentSelected('component2') then
UnZip(Temp+'\component2.zip', 'packs', Temp);
// ...
Though I do not see why you unzip to Temp
/{tmp}
– From your other questions, I'm suspecting that you then use [Files]
to copy from {tmp}
to {app}
using Flags: external
. But you can unzip directly to {app}
!
If you have more components, you will want to factor out the above code to a functions, not to repeat it.
procedure AddDownloadIfComponentSelected(Comp, BaseName: string);
begin
if WizardIsComponentSelected(Comp) then
DownloadPage.Add('https://example.com/' + BaseName, BaseName, '');
end;
procedure UnZipIfComponentSelected(Comp, BaseName, FileName, TargetPath: string);
begin
if WizardIsComponentSelected(Comp) then
UnZip(ExpandConstant('{tmp}') + '\' + BaseName, FileName, TargetPath);
end;
Then you use them like:
AddDownloadIfComponentSelected('component1', 'component1.zip');
AddDownloadIfComponentSelected('component2', 'component2.zip');
UnZipIfComponentSelected('component1', 'component1.zip', 'packs', Temp);
UnZipIfComponentSelected('component2', 'component2.zip', 'packs', Temp);
If you always use 'packs'
and Temp
, you can of course hard-code them in UnZipIfComponentSelected
and you do not have to repeat them in every call.
If you have a LOT of components, you might want to align their and packages' names to be able to automate the download selection – not to have to repeat the above code (not even the function call) for each and every.
Use WizardSelectedComponents
to retrieve a list of selected components. Like this (untested):
var
Components: TStringList;
Component: string;
I: Integer;
begin
Components := TStringList.Create();
Components.CommaText := WizardSelectedComponents(False);
for I := 0 to Components.Count - 1 do
begin
Component := Components[I];
if WizardIsComponentSelected(Component) then
DownloadPage.Add(
'https://example.com/' + Component + '.zip', Component + '.zip', '');
end;
end;
And similarly for unzipping:
for I := 0 to Components.Count - 1 do
begin
Component := Components[I];
if WizardIsComponentSelected(Component) then
UnZip(Temp + '\' + Component + '.zip', 'packs', Temp);
end;