如何在Inno Setup中按用户选择的组件下载并解压指定文件
Inno Setup 组件按需下载与解压进度优化方案
现存问题分析
- 无差别下载解压:当前代码在准备安装阶段直接下载完整的1.4GB压缩包,完全不判断用户选中的组件,导致无论选什么都要处理全部文件,耗时极长。
- 无解压进度反馈:解压时使用了
NO_PROGRESS_BOX标志,系统不显示解压进度,用户无法感知安装状态。
解决方案一:现有单压缩包下的按需解压(快速优化)
如果暂时无法拆分压缩包,可通过只解压选中组件对应目录减少耗时,同时恢复解压进度提示。
修改后的完整代码
[Files] Source: "{tmp}\packs\Sapphic_icons\Dead by Daylight\DeadByDaylight\Content\UI\Icons\README.txt"; DestDir: "{app}"; Components: sapphic; Flags: ignoreversion recursesubdirs createallsubdirs external; Check: IsComponentSelectedAndNeedsInstall("sapphic") [Types] Name: "sapphic"; Description: "Sapphic Pack"; Name: "custom"; Description: "Customized"; Flags: iscustom; [Components] Name: "sapphic"; Description: "Sapphic Pack - WIP*"; Types: custom sapphic; [Code] { —————————— 解压工具函数 ———————————————————————————————————————— } const RESPOND_YES_TO_ALL = 16; // 移除NO_PROGRESS_BOX,显示系统解压进度条 procedure UnZip(ZipPath, SourceDir, 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('无法打开ZIP文件 "%s" 或文件不存在', [ZipPath])); Item := ZipFile.ParseName(SourceDir); if VarIsClear(Item) then RaiseException(Format('在ZIP文件 "%s" 中找不到 "%s"', [SourceDir, ZipPath])); TargetFolder := Shell.NameSpace(TargetPath); if VarIsClear(TargetFolder) then RaiseException(Format('目标路径 "%s" 不存在', [TargetPath])); TargetFolder.CopyHere(Item, RESPOND_YES_TO_ALL); end; { —————————— 组件安装检查函数 ———————————————————————————————————————— } function IsComponentSelectedAndNeedsInstall(ComponentName: string): Boolean; var TargetPath: String; begin // 检查组件是否被选中,且目标目录不存在 Result := (IsComponentSelected(ComponentName)) and (not DirectoryExists(ExpandConstant('{userappdata}\App\packs\' + ComponentName + '_icons'))); Log(Format('组件%s安装检查结果: %d', [ComponentName, Result])); end; { —————————— 下载进度回调 ———————————————————————————————————————— } var DownloadPage: TDownloadWizardPage; function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean; begin if Progress = ProgressMax then Log(Format('文件已成功下载到{tmp}: %s', [FileName])); Result := True; end; { —————————— 初始化向导 ———————————————————————————————————————— } procedure InitializeWizard(); begin DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), @OnDownloadProgress); end; { —————————— 下一步按钮逻辑 ———————————————————————————————————————— } function NextButtonClick(CurPageID: Integer): Boolean; var Temp: String; NeedDownload: Boolean; begin Result := True; if CurPageID = wpReady then begin // 判断是否有选中的组件需要下载解压 NeedDownload := IsComponentSelectedAndNeedsInstall('sapphic'); if NeedDownload then 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}'); // 只解压选中组件对应的目录 if IsComponentSelected('sapphic') then UnZip(Temp+'\packs.zip', 'packs/Sapphic_icons', Temp); except SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK); Result := False; end; finally DownloadPage.Hide; end; end; end; end;
关键修改点
- 移除解压无进度标志:删除
NO_PROGRESS_BOX,让系统显示默认的解压进度窗口,给用户明确反馈。 - 组件按需解压:在
NextButtonClick中判断用户选中的组件,只解压对应目录(如sapphic组件对应packs/Sapphic_icons)。 - 优化安装检查逻辑:新增
IsComponentSelectedAndNeedsInstall函数,同时检查组件是否被选中、目标目录是否存在,避免重复解压。
解决方案二:分组件打包实现真正按需下载(彻底优化)
如果要完全避免下载未选中组件的文件,需将每个组件的资源单独打包,再根据用户选择动态下载对应压缩包。
核心修改思路
- 拆分压缩包:将Sapphic Pack单独打包为
sapphic_packs.zip,其他组件同理。 - 动态添加下载任务:在
NextButtonClick中遍历选中的组件,添加对应压缩包的下载链接。 - 逐个解压对应组件:下载完成后,仅解压当前选中组件的压缩包。
内容的提问来源于stack exchange,提问作者Lilith Helsente
相关产品推荐
相关产品推荐

