[Azure DevOps] 使用 Inno Setup 制作桌面软件安装包
1. 桌面应用程序的 CI/CD
桌面应用程序的 CI/CD 过程和网站有一些不同,毕竟桌面应用程序的“部署”只是将安装包分发到目标位置,连应用商店都不用上,根据公司的管理流程可以很复杂,也可以很简单。在简单的情况下,Azure Pipelines 中一个桌面应用(WPF)的 CI/CD 过程如下:
- 触发器启动 Pipeline
- 构建 WPF 应用程序
- 启动单元测试以确保构建质量
- 创建安装包
- 将安装包复制到目标位置
- 通知用户新安装包已经可以获取
在使用 Azure Pipelines 实现 CI 这篇文章中,我讲解了如何实现第 1、2、3、5 步。至于第 6 步,可以在 Project Settings 的 Notifications 页面中设置使用邮件通知团队成员,也可以参考 使用连接器接收Azure DevOps的通知 这篇文章通过 Teams 发送构建的结果。
现在我们还缺少第 4 步“创建安装包”,这篇文章将讲解如何在 Azure Pipelines 中使用 Inno Setup 创建安装包。
2. 使用 Inno Setup 创建安装包

假设我们已经根据 使用 Azure Pipelines 实现 CI 的做法发布了一个 WPF 应用程序,发布到 Artifacts 的文件将会如上图所示,可以以 Zip 的方式将所有输出文件下载到本地,基本相当于绿色版软件。但我们不能将这个 Zip 包直接发给客户,我们至少还要包括开始菜单和修改注册表什么的一大堆东西,所以需要将 Release 的文件打包到一个安装包中。我的公司通常使用 Inno Setup 制作安装包,在 Azure Pipelines 中使用 Inno Setup 也十分简单,于是这篇文章将使用 Inno Setup 作为制作安装包的例子。
首先我们需要一个 iss 脚本。在 install 目录下创建一个简单的名为 SetupScript.iss 的脚本文件,大部分保留了默认值(懒得修改公司名之类的了),它只是将 Release 目录的内容全部打包起来,内容如下:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "My Program"
#define MyAppPublisher "My Company, Inc."
#define MyAppURL "https://www.example.com/"
#define MyAppExeName "wpf.exe"
#define VersionSourceAssemblyName MyAppExeName
#define BuildOutputFolder "..\wpf\bin\Release\"
#define MyAppFileVersion GetFileVersion(AddBackslash(BuildOutputFolder) + VersionSourceAssemblyName)
#define MyAppCustomerVersion GetStringFileInfo(AddBackslash(BuildOutputFolder) + VersionSourceAssemblyName, "ProductVersion")
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{0B50DAF7-728E-48C7-984F-5E6FDB924490}
AppName={#MyAppName}
AppVersion={#MyAppCustomerVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputBaseFilename=mysetup {#MyAppCustomerVersion}
Compression=lzma
SolidCompression=yes
WizardStyle=modern
VersionInfoCompany={#MyAppPublisher}
VersionInfoVersion={#MyAppFileVersion}
VersionInfoProductName={#MyAppName}
VersionInfoProductTextVersion={#MyAppCustomerVersion}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "{#BuildOutputFolder}{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#BuildOutputFolder}*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
用 Inno Setup 运行一下这个脚本文件确保它正确运行(如果成功的话会在 Installer\Output 目录下生成一个安装程序)。
3. 在 Azure Pipelines 上运行 Inno Setup
把 SetupScript.iss 推送到 Azure Repos 上,然后修改对应的 Pipeline。Pipeline 中需要添加两个任务:
- 一个负责使用 Chocolatey 下载并安装 Inno Setup 的任务
- 一个调用 Inno Setup 运行 SetupScript.iss 的任务
然后修改 CopyFiles 任务,将 Installer\output 目录中的安装包复制到 $(build.artifactstagingdirectory)。修改后的 YAML 文件如下(其中两个 PowerShell 任务即为新增的两个任务):
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller@1
- task: PowerShell@2
displayName: 'Inno setup download'
inputs:
targetType: 'inline'
script: 'choco install innosetup'
- task: NuGetCommand@2
inputs:
restoreSolution: '$(solution)'
- task: VSBuild@1
inputs:
solution: '$(solution)'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: PowerShell@2
displayName: 'Execute Inno Setup script'
inputs:
targetType: 'inline'
script: 'iscc.exe Installer\\SetupScript.iss'
- task: CopyFiles@2
inputs:
SourceFolder: 'Installer\\output'
Contents: '*.exe'
TargetFolder: '$(build.artifactstagingdirectory)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
4. 最后
现在,一个桌面应用程序的 CI/CD 已经基本完成了。当然实际应用中 iss 脚本和 PowerShell 都可以更复杂以便完成更多任务,例如程序签名、检查并安装 .Net Framework 等,这些操作都超出了这篇文章的范畴,如有需要可以参考下面这些链接:
Inno Setup - a free installer for Windows programs
Chocolatey Software - The package manager for Windows
[Azure DevOps] 使用 Inno Setup 制作桌面软件安装包的更多相关文章
- 用Inno Setup制作WEB程序安装包
原文 用Inno Setup制作WEB程序安装包 最近做了一个WEB程序的安装包,我把制作的过程做个介绍,贴出源码给大家做个参考 看看inno 的脚本 [Setup] AppCopyright=tes ...
- Inno Setup制作应用程序安装包
我最近写了一个MFC应用程序,想发给其他的小伙伴玩一玩,直接发了个exe文件过去,结果发现小伙伴那边打不开.原来这个exe文件虽然是MFC静态编译的,但是还依赖了其他几个.dll文件,需要把这几个dl ...
- 用inno Setup制作web项目安装包
http://www.cnblogs.com/xionghui/archive/2012/03/22/2411207.html 用inno Setup制作安装包 新建一个文件夹exambody,放ap ...
- 用inno Setup做应用程序安装包的示例脚本(.iss文件)(
用innoSetup做应用程序安装包的示例脚本(.iss文件),具体要看innoSetup附带的文档,好象是pascal语言写的脚本. 示例1(应用程序.exe,客户端安装): ;{089D6802- ...
- 使用 InstallShield 制作 Delphi 软件安装包
软件版本: InstallShield 12 Delphi 5/7 SQL Server 2005 一.配置软件信息 二.软件安装的需求配置 三.安装架构 四.安装需要的文件 软件的安装路径.可执行文 ...
- 使用Inno Setup 制作软件安装包详细教程(与开发语言无关)
前言:关于如何制作一个软件安装包的教程,与编程语言无关.以下,请看详情~ 1.下载Inno Setup,下载地址:https://jrsoftware.org/isinfo.php 2.下载最新版本即 ...
- 快速创建软件安装包-ClickOnce
大家好,我是沙漠尽头的狼. .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台. 今天介绍使用ClickOnce制作软件安装包,首先我们先了解什么是ClickOne. 1. 什么是Click ...
- 解决Inno Setup制作安装包无法创建桌面快捷方式的问题
转自:http://yedward.net/?id=104 昨天想把个java程序做成exe安装软件,然后就去下载了Inno Setup这个软件安装包制作软件,Inno Setup这个软件确实非常好用 ...
- Inno Step软件安装包制作教程
Inno setup制作软件安装包教程 1,Inno Setup介绍 Inno Setup 是一个免费的安装制作软件,小巧.简便.精美是其最大特点,支持pascal脚本,能快速制作出标准Windows ...
随机推荐
- 将HTML字符串编译为虚拟DOM对象的基础实现
本文所有代码均保存在HouyunCheng / mini-2vdom 虚拟DOM只是实现MVVM的一种方案,或者说是视图更新的一种策略,是实现最小化更新的diff算法的操作对象. 创建扫描器 所有编译 ...
- Day003 类型转换
类型转换 由于java是强类型语言,所以要进行有些运算的时候,需要用到类型转换 低------------------------------------------------------> ...
- 通过CRM系统实现工作流程自动化
灵活运用CRM系统所拥有的自动化功能模块,是公司在快速发展和降低成本的关键保障.不管您的公司规模的大小,您企业的工作流程都必须遵照相同的流程反复操作.这种反复的工作是一个效率黑洞,长久以往会导致人力资 ...
- Gateway导航
简介 最近都在弄微服务的东西,现在来记录下收获.我从一知半解到现在能从0搭建使用最大的感触有两点 1.微服务各大组件的版本很多,网上很多博客内容不一定适合你的版本,很多时候苦苦琢磨都是无用功 2.网上 ...
- [DB] 数据库的连接
概述 集合运算:交,差,并,笛卡尔积 关系运算:选择,投影,连接,除 集合运算是关系运算的基础,关系运算可以用SQL语句表达 连接(join):从两个关系(表)的笛卡儿积中选取属性(列)间满足一定条件 ...
- [bug] eclipse 点击new菜单后没有新建java project或class选项
参考 https://blog.csdn.net/u013001763/article/details/54405758
- 查看报错原因 sshd -t
b for ssh.service failed because the control process exited with error code. See "systemctl sta ...
- Java 线程池 ThreadPoolExecutor 的使用
引言 JAVA 语言为我们提供了两种基础线程池的选择: ThreadPoolExecutor ScheduledThreadPoolExecutor 它们都实现了 ExecutorService 接口 ...
- STM32电路设计注意
以后画STM32的电路板 VDDA一定要接 张JF说 VDDA是给内部的时钟电路供电的 还有一定要留 串口或者 下载调试口(串口) 或者显示器接口 输入输出设备最好都留着 这样才能方便调试
- C++对象内存分布详解(包括字节对齐和虚函数表)
转自:https://www.jb51.net/article/101122.htm 1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数 ...