项目完结,特来总结 Inno Setup 打包

1,697 阅读6分钟

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 是“软件使用许可协议”,基本是一些简介和免责声明啥的,需要用户手动勾选

image.png

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;

安装时选择安装路径

image.png

// 选择安装路径
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

各个模块都集成到了一个安装包中,安装时可选安装哪些模块

两者搭配使用。下面的例子里有二级菜单选择,

image.png

[Types]
Name: "Custom"; Description: "Custom Installation"; Flags: iscustom

[Components] 
Name: Client; Description: Client ; Types: Custom 
;通过 \First, \Second 完成二级菜单
Name: Gateway; Description: Gateway ; Types: Custom 
;通过 exclusive 完成 DMRXPT 的互斥选择            
Name: Gateway\First; Description: Gateway First; Types: Custom; Flags: exclusive;
Name: Gateway\Second; Description: Gateway Second; Types: Custom; Flags: exclusive;  

Files

需要复制哪些文件

image.png

知识点解析:

  1. Source 复制哪个文件
  2. DestDir 复制到哪儿
  3. 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"

启动打包

如何启动打包呢?

  1. Inno Setup 软件中点击开始按钮。
  2. 在控制台输入 "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}

源码地址

gitee.com/bigflowerfa…