Inno Setup 是一款简单易用的免费的 windows 打包工具
本文是个工具文章,整理、记录最近项目中用到的重点。 细节请参考考官方文档
本文并没有高度定制的场景,因为项目没有要求,所以没有深入研究
另外:文末有源码
Inno Setup 的组成
一个安装包最基本的功能就是把代码生成的文件,拷贝到指定路径。但实际远远不止这些,例如:起、停服务,快捷方式、安装相关依赖程序等等
- [Setup] 基本配置
- [Registry] 注册表修改
- [Languages] 国际化词条(安装过程中,可以选择哪些语言安装)
- [Code] 自由编码部分,一些复杂的场景,需要自己写代码搞定
- [Types] + [Components] 需要安装哪些模块?可勾选的决定安装某些网元(如只安装客户端、不安装服务器)
- [Files] 需要复制哪些文件
- [dirs] 主动创建文件夹
- [Tasks] 这个忘了干啥用的了(狗头保命)好像是是否需要创建桌面快捷方式的页面
- [Icons] 创建桌面快捷方式
- [Run] 运行一些程序、文件。 和 [Files] 搭配使用,一个复制到电脑上,一个运行
- [UninstallDelete] 卸载时,需要主动删除哪些文件 (Inno Setup 会自动删除,但程序运行后生成的,或是变化的, Inno Setup 不会删除,这时就需要主动删除)
- [UninstallRun] 卸载时,需要运行哪些
各模块拆分说明
Setup
项目的基本配置
配置应用名称,图标,版本等信息,没有难点,此处不再赘述
Registry
注册表修改
给程序 Summer.exe 增加管理员权限
[Registry]
Root: HKCU ;SubKey:SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers;ValueType:string;ValueName:{app}\Client\Summer.exe;ValueData:"RUNASADMIN" ;Flags:uninsdeletekeyifempty uninsdeletevalue;
Languages
安装包支持哪些语言
[Languages]
Name: "cn"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"; LicenseFile:.\Licenses\License-CN.txt
Name: "en"; MessagesFile: "compiler:Default.isl"; LicenseFile:.\Licenses\License-EN.txt
InnoSetup基础版本自带了一些语言,但是没有简体中文(mmp) 所以需要自己下载,这个我放到 Demo 里了,需要手动拷贝到 InnoSetup 的安装路径的 Language 下(C:\Program Files (x86)\Inno Setup 6\Languages),打包时使用的多语言都在这里
LicenseFile 是“软件使用许可协议”,基本是一些简介和免责声明啥的,需要用户手动勾选
Code
自由编码部分,一些复杂的场景,需要自己写代码搞定
安装初始化时,停服务、进程
通过调用 cmd 命令实现停止服务、停止进程
function InitializeSetup(): Boolean;
var
result1: Integer;
result2: Integer;
begin
// 脚本停止服务、进程
ShellExec('', 'cmd.exe', 'cmd /c net stop "MyGateway"', '', SW_HIDE, ewWaitUntilTerminated, result1);
ShellExec('', 'cmd.exe', 'cmd /c taskkill /f /im Summer.exe', '', SW_HIDE, ewWaitUntilTerminated, result2);
// True:继续, False:不再安装
Result := True;
end;
检测程序是否安装
通过检测注册表信息,判断程序是否已经安装。 如果检测到 PG 数据库已经安装,则不再重复安装
// 通过注册表, 检测 PG数据库 是否已经安装
function IsPGNeedInstall(): Boolean;
begin
// 因为 32位 和 64位 的缘故,增加 HKML64 判断
if RegValueExists(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PostgreSQL 14', 'DisplayVersion')
or RegValueExists(HKLM64, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PostgreSQL 14', 'DisplayVersion') then
begin
Result := False;
end
else
begin
Result := True;
end;
end;
判断文件是否存在
function IsFileExist(filePath: string): Boolean;
begin
if (FileExists(filePath)) then
begin
Result := True;
end
else
begin
Result := False;
end;
end;
安装时选择安装路径
// 选择安装路径
var
SelectDirPage: TInputDirWizardPage;
procedure InitializeWizard;
begin
SelectDirPage := CreateInputDirPage(wpSelectDir, 'Select Custom Install Path', 'Select the folder where you want to install the application.', 'Select a folder:', False, '');
// 没啥用,为了好看
SelectDirPage.Add('');
// 给一个默认路径
SelectDirPage.Values[0] := ExpandConstant('{#MyAppSetupBaseDir}');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID = SelectDirPage.ID then
begin
// 选完路径后,后面追加一个应用名
WizardForm.DirEdit.Text := SelectDirPage.Values[0]+'\{#MyAppName}';
end;
Result := True;
end;
Types + Components
各个模块都集成到了一个安装包中,安装时可选安装哪些模块
两者搭配使用。下面的例子里有二级菜单选择,
[Types]
Name: "Custom"; Description: "Custom Installation"; Flags: iscustom
[Components]
Name: Client; Description: Client ; Types: Custom
;通过 \First, \Second 完成二级菜单
Name: Gateway; Description: Gateway ; Types: Custom
;通过 exclusive 完成 DMR、XPT 的互斥选择
Name: Gateway\First; Description: Gateway First; Types: Custom; Flags: exclusive;
Name: Gateway\Second; Description: Gateway Second; Types: Custom; Flags: exclusive;
Files
需要复制哪些文件
知识点解析:
- Source 复制哪个文件
- DestDir 复制到哪儿
- Components: Gateway 如果安装网关,则复制这个文件
;pg 数据库 安装文件
#define pgExe "postgresql-14.6-1-windows-x64.exe"
; onlyifdoesntexist 如果文件存在,则不复制
Source: "version.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#pgExe}"; DestDir: "{app}"; Flags: ignoreversion onlyifdoesntexist; Check: IsPGNeedInstall; Components: Gateway;
; 如果安装了客户端或网关,则复制 Common 下的所有文件,到安装目录下的 Common 文件夹内
Source: "Common\*"; DestDir: "{app}\Common\"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: Server Gateway;
; 如果安装了First网关,则复制 First 下的所有文件,到安装目录下的 \Gateway\First 文件夹内
Source: "First\*"; DestDir: "{app}\Gateway\First\"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: Gateway\First;
Dirs
需要创建哪些文件夹
举例:在 C:\ProgramData
下创建文件夹 Record
Name:"C:\ProgramData\Record"
Tasks
是否需要创建桌面快捷方式
增加后,可在安装过程中,勾选是否需要创建快捷方式
Icons
创建桌面快捷方式
- Check: 可用于判断是否需要创建该快捷方式
- IsFileExist('文件路径') 在
Code
中写的方法,用于判断文件是否存在
[Icons]
; 开始菜单中创建快捷方式:应用的快捷方式
Name: "{group}\{#MyAppName}"; Filename: "{app}\Client\{#ClientExeName}";
; 开始菜单中创建快捷方式:卸载应用的快捷方式
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
;WorkingDir: "{app}" 创建桌面快捷方式
Name: "{commondesktop}\Summer"; Filename: "{app}\Client\{#ClientExeName}"; WorkingDir: "{app}\Client"; Check: IsFileExist('{#MyAppSetupBaseDir}{#MyAppName}\Client\{#ClientExeName}')
Run
文件复制结束后,需要运行哪些程序
[Run]
;静默安装:Parameters: /q
;安装C++运行时
Filename: "{app}\dependence\vcredist2015-2019_x86.exe";Parameters: /q; StatusMsg: "Install C++ 2019 x86..."; Check: IsVCPNeedInstall('19', 'x86');
;如果安装了网关,并且数据库没安装过,则安装数据库
Filename: "{app}\{#pgExe}"; StatusMsg: "Install postgresql-14.6-1-windows-x64.exe ..."; Check: IsPGNeedInstall; Components: Gateway;
UninstallDelete
卸载时,需要主动删除哪些文件
该方法有一定作用,但是还是存在无法删干净的情况。
网上还有一种方法,结束后调用脚本去删除文件,理论上可行,但是我没实践过
[UninstallDelete]
Type: filesandordirs; Name: "{app}"
Type: filesandordirs; Name: "C:\ProgramData\Log"
UninstallRun
卸载时,需要运行哪些
卸载程序时,可以调用脚本,执行一系列操作,例如:将注册的服务干掉、删除注册表、去掉防火墙规则等
[UninstallRun]
Filename: "{app}\{#MyAppUnregisterGatewayBat}" ; Flags: runhidden skipifdoesntexist
其他
宏定义
#define MyAppName "Summer"
启动打包
如何启动打包呢?
- Inno Setup 软件中点击开始按钮。
- 在控制台输入
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "你的打包代码.iss"
动态设置版本号
为了让别人能够快乐的启动我的打包,我写了个一个脚本 inno.bat
,只有一句话
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "innosetup.iss" /DVersion=%1
这里允许别人调用我的脚本的时候,传入一个参数。 这个参数在我代码中,会读取到,这样打包的时候就能把版本号打到包里了。
别人只需要在控制台这样:
inno.bat "V1.0.01.000"
代码中这样设置的:
;如果没有传版本号,则给个默认版本号
#ifndef Version
#define Version = 'V1.0.00.000';
#endif
[Setup]
AppVersion={#Version}