尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

深入Inno Setup:打造专业级自定义安装界面的全解析

深入Inno Setup:打造专业级自定义安装界面的全解析 简介面向桌面软件封装与安装包定制开发者的 Inno Setup 自定义安装界面资源包。基于 Inno Setup 增强版进行封装已内置对 .NET FormWork 4 的封装支持非常适合需要在安装过程中自定义品牌标识、安装界面视觉风格以及部署参数的 Windows 项目团队。资源包共包含 136 个文件包体大小约 105.4MB其中 isl 与 iss 脚本用于控制安装界面逻辑png/psd 图片素材可供直接替换界面视觉元素dll 与 exe 文件是封装所需的重要组件和辅助工具此外还包含图标、授权说明、通用配置等文件目录结构按用途划分便于查找修改。使用时只需替换 app 目录下的程序文件更新 temp 目录下的界面图片再根据项目需要修改 Code.iss 界面脚本与 version.h 配置文件即可调整应用名称、公司名称、版本号等关键参数实现快速生成带有专属视觉的安装包。目前该资源已有 1741 人学习浏览适合中高级 Windows 开发者、软件打包工程师以及需要建立统一安装品牌的技术团队参考使用。1. 从默认向导到自己的界面Inno Setup 的自定义空间有多大Inno Setup 一键生成的是蓝色背景、固定布局的向导但很多人不知道它真正的默认界面只是 WizardForm 这个顶层表单所有可见区域都可以从脚本端改写。所谓自定义安装界面并不是换几个图片那么浅而是把静态资源、窗口属性和 Pascal 事件脚本组合起来重新安排用户安装软件时的每一步反馈。它能解决的问题包括品牌化包装、收集序列号、动态跳转、自定义完成页行为。这套方案适合已经能跑通一个基础 .iss 脚本、想在界面上加自己控件的工程人员。下面按窗口结构 → 静态资源 → 自定义页面 → 高级交互 → 可验证性的顺序展开每个环节都给可以直接放进编译器的代码和参数。2. 安装界面的骨架先清楚窗口由谁画出来再谈自定义2.1 Inno Setup Compiler 编译了什么运行时界面从哪来一个安装程序不是把 .iss 里的界面描述逐行画出来而是先由 Inno Setup CompilerISCC.exe把脚本编译进 setup.exe运行时由安装引擎实例化 TSetupForm再按脚本注册的事件初始化。所以你会看到 WizardForm 这个全局变量它就是整个向导对话框。位图和字符串只负责消费真正改变布局的入口是 [Setup] 段和 [Code] 段里的事件。写 Inno Setup 自定义安装界面不需要懂编译器内部实现但要理解三件事第一向导页是容器 TWizardPage每个页面有自己的 Surface 用来放控件第二[Code] 中的 InitializeWizard 是整个运行时界面的初始化时机第三页面切换有 CurPageChanged、ShouldSkipPage、OnNextButtonClick 等钩子能覆盖绝大部分交互需求。常见误区是去改已知的安装包资源或者寻找第三方皮肤组件。实际上官方脚本模型已经开放了窗口句柄、父容器和字体对象标准做法是在 [Setup] 配好基础视觉再用 InitializeWizard 做运行时微调。这样升级安装引擎时不用重新做资源替换。2.2 与界面直接相关的 [Setup] 参数一览参数作用常用值WizardStyleclassic 或 modern决定默认视觉基模modernWizardSizePercent窗口相对默认大小的百分比缩放整个向导100WizardImageFile欢迎页与完成页左侧的大图images\wizard.bmpWizardSmallImageFile向导页右上角小图images\small.bmpWindowTitle安装程序窗口标题栏文字{#MyAppName} 安装BackColor / BackColor2欢迎页两侧渐变背景色$FFFFFF / $F2F2F2SetupIconFile控制安装程序 exe 图标icons\app.ico这些参数在编译期写入安装文件头运行时不占脚本编译消耗。WizardStylemodern 不等于能做圆角窗口它只是让默认按钮、字体和边距贴近新式软件安装包如果追求完全统一的产品视觉通常会把 WizardStyle 固定下来再用 WizardSizePercent 控制整体放缩比例。WizardSizePercent 建议按目标分辨率的 80% 计算不要盲目调大否则在小屏虚拟机上按钮会被挤出可视区。2.3 InitializeWizard 是第一个要写的函数例程看起来简单但能验证脚本运行时是否真的握住了窗口控制权。procedure InitializeWizard(); begin WizardForm.Caption : AutoDeploy 安装向导; WizardForm.PageNameLabel.Font.Color : clNavy; WizardForm.PageDescriptionLabel.Font.Name : Microsoft YaHei; WizardForm.PageDescriptionLabel.Font.Size : 18; WizardForm.MainPanel.Color : clWhite; end;这段代码把 WizardForm.Caption 改为安装项目名把页面左上角标题文字颜色改成深蓝把描述文字换成微软雅黑并放大到 18 号主面板背景改成纯白。要注意 WizardForm.MainPanel 是 TNewPanel背景色只作用于中间主区域两侧渐变仍由 [Setup] 的 BackColor 控制。字体名要写系统里真实存在的否则 Windows 会回退到宋体让布局侧边距变宽。在脚本里判断效果的方法是给这个函数临时加一行 WizardForm.Color : clRed;编译运行后如果整个窗口变红说明窗口句柄和控件链已经拿到。把这句话删掉再继续做资源替换。这种从一个小函数摸清对象模型的习惯能省掉后面排查页面坐标的很多时间。3. 用静态资源做品牌化界面换 Logo、横幅和标题栏3.1 先解决位图资源尺寸、位深和对齐的约定静态资源是自定义安装界面投入产出比最高的一层。先准备两张 BMP一张用于欢迎页/完成页左侧主图一张用于右上方的小 Logo。常见做法是用 24 位真彩 BMP避免直接使用 JPG因为 Inno Setup 对 JPG 需要额外处理而 BMP 的兼容性最稳定。主图宽度建议取 156 或 164高度按实际设计比例做编译时会以 WizardSizePercent 等比缩放但不建议做得比默认位图更宽否则在 1024×768 虚拟机上两侧空间会很挤。[Setup] WizardStylemodern WizardSizePercent100 WizardImageFileassets\wizard_left.bmp WizardSmallImageFileassets\wizard_top.bmp SetupIconFileassets\installer.ico WindowTitleOctoSuite 安装向导 BackColorclWhite BackColor2$E8EBEF WindowResizableno这段配置的意思窗口采用 modern 风格整体大小保持默认左侧主图来自 wizard_left.bmp右上小图来自 wizard_top.bmp安装程序图标换成 installer.ico标题栏直接写死产品名欢迎页背景是白色到浅灰的纵向渐变窗口不允许用户手动拉伸。WindowResizableno 是自定义界面里容易被忽略的开关如果你处理了 WizardSizePercent 而不关这个用户在 4K 屏上拖动窗口边缘会把控件布局扯乱。位图属性推荐值说明格式24-bit BMP无 alpha 需求时最稳定透明区域32-bit BMP WizardImageAlphaFormatpremultiplied需要透明时启用水平尺寸156 或 164 像素跟随官方默认主图宽度色彩模式RGB不要用 CMYK 转出来带色差的文件对齐上下左右像素边界对齐避免边缘出现杂色线条WizardImageAlphaFormatpremultiplied 是透明位图的关键开关加了之后 Inno Setup 才会把 BMP 的 alpha 通道当作透明度处理。不少人在这一步翻车用图片工具导出的 32 位带 alpha BMP忘了在 [Setup] 里声明结果透明区域变成黑色或白色块。反过来如果只是简单的非透明图别开这个参数开了也看不出区别。3.2 在 InitializeWizard 里做运行时微调字号、间距、进度条静态资源能做的事到 [Setup] 配置为止剩下的细节交给脚本。比如要让品牌色铺满页面也要把进度条颜色同步成品牌色procedure InitializeWizard(); begin WizardForm.PageNameLabel.Caption : 把 OctoSuite 安装到你的开发机; WizardForm.ProgressGauge.Parent.Color : $E8EBEF; WizardForm.Bevel1.Visible : False; WizardForm.Bevel.Visible : False; end;ProgressGauge.Parent.Color 是改进度条周围背景ProgressGauge 本身不提供 Color 属性因为它是 TNewProgressBar在 Windows 主题下会忽略颜色。Bevel1 和 Bevel 是底部面板和主面板之间的斜线凹槽去掉后界面更干净。注意别在 InitializeWizard 里改 ProgressGauge.Visible它不是所有页面都会重新触发提前隐藏会导致安装过程中看不到进度反馈。这种运行时改字体和间距的做法和 [Setup] 静态参数最大的区别是可以做条件判断。比如在 Win11 上把字体换成系统默认的 Segoe UI Variable在 Win10 上仍然用 Segoe UI。判断系统版本需要调用 GetVersionEx这里不展开但思路是先把分支记在 InitializeWizard 里再根据当前页面调整控件坐标。3.3 把按钮文案和状态提示也纳入品牌范围界面不只有图和布局按钮文字、复选框文字、错误提示同样影响观感。Inno Setup 的 [Messages] 段允许覆盖运行时字符串下面是一组最小覆盖[Messages] SetupWindowTitleOctoSuite 安装 ConfirmUninstall真的要卸载 OctoSuite 吗 ButtonBack上一步 ButtonNext下一步 ButtonInstall开始安装 ButtonFinish完成SetupWindowTitle 会覆盖安装程序窗口标题ButtonInstall 是进入安装页面后安装按钮上的文字。这些文案在编译期合并进 Default.isl 对应的语言文件所以多语言项目要注意每个 [Languages] 都补上相同键。另一个隐藏点位是 StatusMsg 和 InstallingLabel它们决定安装进度页的提示语建议一并覆盖否则顶部标题改了、中间还是默认英文。对于 Inno Setup 制作安装包的工程一般还会在 [Messages] 里覆盖 ClickNext 的默认文案。这不是必须但安装包产品化之后用户看完向导第一屏就会对软件质量有判断文案和位图都值得花时间统一。4. 在向导中间插入自定义页面CreateCustomPage 与控件的生命周期4.1 做一个能收集序列号的自定义页面界面自定义到这一步已经不只是换皮而是让安装程序具备表单能力。最常见的落地场景是收集序列号或部署参数。要新增一个向导页只需要在 InitializeWizard 里调用 CreateCustomPage然后往页面的 Surface 上摆控件。var SerialPage: TWizardPage; SerialEdit: TNewEdit; SerialLabel: TNewStaticText; procedure SerialPageActivate(Sender: TObject); begin SerialEdit.SetFocus; end; function SerialPageNext(Sender: TWizardPage): Boolean; begin Result : Trim(SerialEdit.Text) ; if not Result then MsgBox(序列号不能为空请检查后重试。, mbInformation, MB_OK); end; procedure InitializeWizard(); begin SerialPage : CreateCustomPage(wpWelcome, 序列号验证, 请输入采购 OctoSuite 时获得的序列号。); SerialLabel : TNewStaticText.Create(SerialPage); SerialLabel.Parent : SerialPage.Surface; SerialLabel.Caption : 序列号; SerialLabel.Left : 16; SerialLabel.Top : 12; SerialLabel.AutoSize : True; SerialEdit : TNewEdit.Create(SerialPage); SerialEdit.Parent : SerialPage.Surface; SerialEdit.Left : 80; SerialEdit.Top : 8; SerialEdit.Width : 240; SerialPage.OnActivate : SerialPageActivate; SerialPage.OnNextButtonClick : SerialPageNext; end;这段代码有几个关键点。CreateCustomPage(wpWelcome, ...) 返回 TWizardPage 对象意思是把这个新页插在欢迎页之后作为第二页。控件创建后必须设置 Parent : SerialPage.Surface如果不设置控件不会显示这是新脚本最常见的问题。Left/Top 是从页面内容区左上角开始计算不是相对于整个窗口所以 16 和 12 已经贴近左侧边缘。OnNextButtonClick 返回 False 时用户点下一步会被拦在当前页并弹出提示框返回 True 则继续进入许可证页。OnActivate 事件在页面每次被切换到前台时触发这里用来把光标放回输入框。这个事件也可以用来做按需刷新比如从上一个页面带来路径选择后重设控件的可见性。事件签名要和 Pascal 完全一致Sender 类型写错编译器会直接报不相容。4.2 把输入值带到安装逻辑注册表、配置文件与安装后操作自定义页面收集到的值不能只停留在界面层。读取它的时机要在用户填完、用户点下一步之后也就是安装开始前。最常见的位置是 CurStepChanged 里的 ssInstall 阶段。procedure CurStepChanged(CurStep: TSetupStep); begin if not IsUninstaller and (CurStep ssInstall) then begin SaveStringToFile(ExpandConstant({app}\license.txt), SerialEdit.Text #13#10, False); RegWriteStringValue(HKLM, Software\OctoSuite, Serial, SerialEdit.Text); end; end;ExpandConstant({app}) 会把常量展开成用户最终选择的安装目录SaveStringToFile 的第三个参数 False 表示覆盖而不是追加这样重复安装时 license.txt 不会残留旧值。RegWriteStringValue 第二个参数必须是完整注册表路径函数会自动创建缺少的路径。如果产品设计成按用户目录安装HKLM 可能会因为没有权限写入而返回 False这时要改用 HKCU或者在页面下方放一个仅当前用户复选框。在卸载逻辑里读取序列号是另一个常见需求。CurStepChanged 在卸载时也会跑所以函数开头必须加 IsUninstaller 判断否则会尝试在卸载流程中重新写入配置。除此之外SerialEdit 对象在卸载时并不存在直接引用会引发访问空对象错误这也是自定义页面变量最常见的崩溃来源。4.3 用 ShouldSkipPage 和复选框控制页面走向有些安装界面不需要一直显示序列号页可能企业部署包走静默参数个人试用版才要求填写。Inno Setup 提供的 ShouldSkipPage 函数可以根据运行时状态跳过任意页面。function ShouldSkipPage(PageID: Integer): Boolean; begin Result : False; if PageID SerialPage.ID then Result : not IsTaskSelected(custom\serial); end;这段脚本的语义只有用户在任务列表中勾选了填写序列号任务才显示 SerialPage。SerialPage.ID 是 CreateCustomPage 返回页的唯一标识不能写死整数。IsTaskSelected(custom\serial) 检查 [Tasks] 段里的任务名任务名可以在页面上以复选框形式呈现常见做法是新建一个自定义任务页把企业部署、语言包等选项放一起。用这种方式控制页面走向比直接改 OnNextButtonClick 更干净它对上一步和下一步都生效不会出现用户点错方向导致页面错乱。配合复选框动态勾选甚至可以在一个页面里做多种安装路径的分流。需要理解几个钩子的边界钩子函数触发时机控制范围ShouldSkipPage(PageID)每次进入页面之前返回 True 直接跳过该页Page.OnNextButtonClick点击下一步后离开页面前返回 False 留在当前页Page.OnActivate页面变为当前页刷新控件、设置焦点CurPageChanged(CurPageID)页面完成切换后读取当前页控件状态判断条件里别放 MsgBoxShouldSkipPage 在向导初始化阶段会被调用多次弹窗会干扰用户。5. 高级自定义与常见崩溃控件方法、动态列表和排查表5.1 在自定义页面里做动态列表TNewListBox 与 TNewButton收集参数之外自定义界面还经常要充当轻量级管理工具让用户勾选组件、确认要部署的路径列表。这里以添加一个需要安装后拷贝的配置文件为例做一个可操作的列表页。var FilePage: TWizardPage; FileList: TNewListBox; AddButton: TNewButton; InfoLabel: TNewStaticText; procedure AddButtonClick(Sender: TObject); begin FileList.Items.Add(config\default IntToStr(FileList.Items.Count 1) .ini); InfoLabel.Caption : 已添加 IntToStr(FileList.Items.Count) 个文件; end; procedure InitializeWizard(); begin FilePage : CreateCustomPage(wpSelectComponents, 附加配置, 选择需要随应用一并安装的配置文件。); FileList : TNewListBox.Create(FilePage); FileList.Parent : FilePage.Surface; FileList.Left : 16; FileList.Top : 16; FileList.Width : 280; FileList.Height : 120; AddButton : TNewButton.Create(FilePage); AddButton.Parent : FilePage.Surface; AddButton.Caption : 添加默认配置; AddButton.Left : 312; AddButton.Top : 16; AddButton.Width : 96; AddButton.OnClick : AddButtonClick; InfoLabel : TNewStaticText.Create(FilePage); InfoLabel.Parent : FilePage.Surface; InfoLabel.Caption : 已添加 0 个文件; InfoLabel.Left : 16; InfoLabel.Top : 148; InfoLabel.AutoSize : True; end;TNewListBox 是 Inno Setup 对标准 ListBox 的封装Items.Add 可以在运行时追加行。这里的 OnClick 事件处理函数签名是 Sender: TObject和 Delphi 的事件模型一致。添加按钮放在列表右侧当窗口用 WizardSizePercent100 时不至于被 Next 按钮遮住。注意按钮的 OnClick 只处理一次鼠标点击键盘回车不会触发如果要无障碍支持应该处理表单级键盘事件大多数安装包不做这个是因为页面会通过回车直接执行向导默认按钮。这个列表的值如果需要在安装阶段使用遍历 FileList.Items 并写入目标目录即可。Items.Strings[I] 读出的就是显示文本不需要再保存到别的全局变量。只要 FileList 是全局变量在安装阶段仍然可以访问。5.2 自绘页面背景和加载位图的取舍想做出区域渐变的品牌背景有两条路线一种是直接在页面的 Surface.Canvas 上画另一种是把重度视觉放到 TImage 控件里。前者代码短但窗口偶尔会残留上一次绘制的痕迹。一般只在 OnActivate 里做纯色或者简单线条不使用 Canvas 画复杂图形。procedure FilePageActivate(Sender: TObject); begin FilePage.Surface.Canvas.Brush.Color : $F5F7FA; FilePage.Surface.Canvas.FillRect(FilePage.Surface.ClientRect); end;这段代码会在每次进入页面时用浅蓝色铺满内容区。问题在于窗口背景刷新和页面重绘是两套机制如果用户拖动窗口边缘或者系统主题刷新这个颜色会被擦掉。要长期保持背景应该预先创建一个 TImage 并设置 Stretch : True把位图作为页面底图或者直接处理 WM_ERASEBKGND 消息。对普通安装程序来说TImage 方案已经足够自绘反而会引入不可预测的闪烁。方案开发成本视觉上限适用场景Canvas 自绘低中纯色背景、简单几何块TImage 位图中高品牌底图、渐变、复杂纹理外部组件接管窗口高极高完整换肤很少推荐选择方案时还要考虑 WizardSizePercent 缩放。TImage 里位图在缩放后会拉伸变形Canvas 自绘则会被 Windows 自动重绘不同缩放级别下坐标需要重新计算。做多分辨率适配时最可靠的方式是保持 WizardSizePercent100用固定坐标布局不做窗口缩放。5.3 自定义安装界面最常出现的 4 个崩溃点症状原因处理方式控件不显示忘了设置 Parent : Page.Surface补 Parent 赋值检查页面是否被 ShouldSkipPage 跳过一点下一步就退回上个页面OnNextButtonClick 函数签名不对确认返回值是 Boolean且没有提前 Exit默认 Result 要按逻辑设置位图边缘出现红边BMP 未按 4 字节对齐用 24 位 BMP 重新保存关掉 alpha 格式自定义页在高分屏上按钮挤成一团没有固定 WizardSizePercent在 [Setup] 里设 WindowResizableno按 125% 做基准布局这些坑隐蔽的地方在于它们往往只在特定机器或者特定版本 Windows 上出现。红边问题在 Win11 上比 Win10 更明显因为新主题会启用更强的透明效果按钮错位则通常出现在修改了系统缩放比例的笔记本上。做脚本排错时编译脚本本身能解决的调试有限直接在干净虚拟机里跑安装包比看编译输出更可靠。6. 用 /LOG 和干净虚拟机验证自定义界面的每个状态自定义安装界面不像普通业务程序有单元测试框架最实用的验收手段是命令行日志和系统快照。编译产物 setup.exe 本身支持一组调试参数其中 /LOG 会把运行时消息写进文件/SAVEINF 和 /LOADINF 能重放用户输入适合回归测试。setup.exe /LOGD:\logs\install_r1.log /SAVEINFD:\logs\install_r1.inf运行这一条后用户手动点完整个安装流程install_r1.inf 会记录每个向导页的输入结果。第二次运行时改用 /LOADINF 加载这份文件安装程序会按上一次的选择自动跳页不需要人工重新点。配合 [Setup] 里的 PrivilegesRequiredadmin可以验证自定义页面在 UAC 弹窗之后是否还能保持尺寸。看日志时重点找 InitializeWizard 之后的行如果某一页创建时抛了异常日志会在页面初始化附近卡住。另外在代码里人为输出到日志也是一种做法procedure CurPageChanged(CurPageID: Integer); begin if CurPageID SerialPage.ID then Log(enter serial page); end;Log 函数在带 /LOG 运行时会自动把文本写入日志这比弹 MsgBox 调试靠谱得多。验证界面时还要准备一个干净 Windows 虚拟机系统字体、缩放比例和 DPI 都要和真实部署环境一致。重点检查三处WizardSizePercent100 时自定义页最右侧按钮不被 Next 遮挡切换页面时文字和位图不闪烁卸载流程中用 IsUninstaller 分支后再读自定义页变量不崩溃。最后把 /LOG 输出的文件保留到发布记录里作为界面版本验收的原始凭证。本文还有配套的精品资源点击获取
返回列表