Electron App 安装包定制 -- Inno Setup 脚本 Pascal Scripting 初探
在做 Electron 项目时,有个需求是安装包安装时要给客户机上装上某个软件
在查看 Inno Setup 官网后发现是通过 .iss 脚本编写实现自定义安装过程
可在 .iss 内可以添加脚本为安装过程添加逻辑
为了测试方便我用 vite 新建一个全新的 electron 项目
用的是这个脚手架 https://github.com/electron-vite/electron-vite-vue
用其它脚手架也行,反正我们对 app 内容本身并不关注,只关心制作安装包
新建 electron 项目
安装注意事项(都是我踩过的坑..)
yarn config get registry
我用的是这个 https://registry.npm.taobao.org/
yarn create electron-vite
项目名 first-electron
模板我选了 vue ,其实无所谓我们只是跑个electron demo 目的是打包而不是开发
Project name: first-electron
Project template: Vue
成功后
cd first-electron
yarn
yarn dev
项目应该跑起来了可以看到 electron 窗口
关掉项目, 下一步测一下打包功能
编译打包 app
项目已经帮你整合了 electron-builder
直接运行打包命令
yarn build
大概率会失败

从 github 拉 electron 失败
需要从镜像服务器,设置 electron_mirror 到专门镜像 后再打包

yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/
yarn build
成功后在项目 first-electron\release 目录下就是编译完成的 electron app 了
我的是在 first-electron\release\0.0.0 目录下,0.0.0 一看就是软件版本号了
项目根目录的 electron-builder.json5 就是 electron-builder 配置文件
配置文件内的 "output": "release/${version}" 就是定义编译后的文件目录,一般不会去改
first-electron_0.0.0.exe 这个文件就是单独文件的安装版,双击安装时会有安装过程
win-unpacked 就是绿色版, 安装包的制作就是把这个文件夹内的文件进行打包
安装包自定义安装过程
如果想对安装包安装过程进行自定义
那么首先电脑上先安装 Inno Setup Compiler, 再创建 setup.iss 文件

通过 ide 新建 .iss 文件

过程如下:
打开 Inno Setup Compiler
新建一个 Inno Setup Script Wizard 开始创建 .iss 脚本文件
按提示一步步往下走,可以选择填写 app 名字,版本,公司之类的信息这些都不重要
直到
Application FilesApplication main executable file 原默认的 Myprog.exe 主执行文件变更到我们自己 first-electron 的主执行文件,如下:
first-electron\release\0.0.0\win-unpacked\first-electron.exe
另外 Other application files: 这一项点击 Add folder... 按钮
把 win-unpacked 整个文件夹也添加进来
继续按提示往下走,直到 Compiler Settings 这一页
Custom compiler output folder: 选择打包文件输出目录
我选择输出到 first-electron\dist-setup 目录
继续按提示往下走,最后会让你保存成 .iss 文件,这个 .iss 文件就是打包脚本了
我在这个例子中输出文件保存为了 setup.iss
先不动这个脚本。直接编译,完成后可以在 first-electron\dist-setup 看到 windows 安装包了
安装程序完成后调用其它程序
比如主程序安装完后想自动执行安装东方财富的的安装文件 “dfcft8.exe”
(别问为什么是 “东方财富” 这个安装包,我的电脑的下载文件夹内刚好看到有这个.exe 执行文件就用这个来测试吧)
为什么要做这么流氓的事? 这只是举个例子而已!
其实,真实项目中有可能是客户机器上缺少某种环境或文件之类的东西,那么你可以利用此方法帮用户安装上
让我们开始吧。 非常的简单!
修改之前保存的 setup.iss 文件
在 setup.iss 文件中找到 [Run] 节点添加如下代码:
[Run]
Filename: "{app}\resources\bin\dfcft8.exe"; Description: ""; Flags: nowait postinstall skipifsilent
使用 Inno setup compiler 编译该文件
安装程序最后会显示这样的画面:

点击 “完成” 按钮就会出现以下画面:

非常简单!
能不能在安装开始前就调用某个程序?
上面说的是安装程序安装完成后执行另外的一个程序,那么如果想在安装程序安装前执行呢?
[code]节点脚本控制安装过程
需要 Pascal 脚本了, 开始吧!
说实话作为长期使用 Javascript 的我来说第一次接触 Pascal Scripting 我心里一万头xx马奔腾而过
而且我看 Inno Setup Compiler 官网 <jrsoftware.org> 的大概意思是 Pascal Scripting 不太好弄
官方建议用户从
Inno Setup 6\Examples安装目录下的 Examples 目录下参考官方提供的脚本例子
在 setup.iss 文件内添加 [code] 节点
这个节点允许你为安装过程添加逻辑,可细化到安装的每一步
它通过在 [code] 节点下暴露 Event Functions 实现,比如:
- function InitializeSetup(): Boolean;
- procedure DeinitializeSetup();
- function InitializeUninstall(): Boolean;
- ...
我姑且把它理解为生命周期吧!
那么如果想在安装开始时就调用
使用 InitializeSetup 并在其内用 Exec 方法调用 'dfcft8.exe'
下面实现安装过程开始之前前调用
[code]
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
begin
ExtractTemporaryFile('dfcft8.exe');
Exec(ExpandConstant('{tmp}\dfcft8.exe'), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
Log('InitializeSetup called');
Result := true
end;
为 setup.iss 添加上面代码后用 Inno Setup Compiler Ide 按 F9 或 Run 菜单 Run选项 "编译并启动"
安装包启动后点击"确定"按钮,Ide 会输出日志,也可以看到东方财富的安装程序也启动了

注意日志输出画面中的 这两句:
[15:19:26.074] Created temporary directory: C:\Users\ADMINI~1\AppData\Local\Temp\is-8P52P.tmp
[15:19:26.082] Extracting temporary file: C:\Users\ADMINI~1\AppData\Local\Temp\is-8P52P.tmp\dfcft8.exe
意思是先建个临时文件夹,再从安装包中先解压出 "dfctt8.exe" 这个文件放到临时文件夹内
此时安装目录内是取不到文件的, 因为我们的 first-electron 程序还没有安装成功,也不会在客户电脑上有安装目录
只能从安装包这个压缩文件内解压获取临时文件
这是 setup.iss 现在的代码
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "first-electron"
#define MyAppVersion "1.5"
#define MyAppPublisher "My Company, Inc."
#define MyAppURL "https://www.example.com/"
#define MyAppExeName "first-electron.exe"
#define MyAppAssocName MyAppName + " File"
#define MyAppAssocExt ".myp"
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
[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={{72C0FB3C-108B-4530-8D27-5D31B5349C3C}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
ChangesAssociations=yes
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=C:\Users\Administrator\Desktop\first-electron\dist-setup
OutputBaseFilename=first-electron-setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "C:\Users\Administrator\Desktop\first-electron\release\0.0.0\win-unpacked\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Administrator\Desktop\first-electron\release\0.0.0\win-unpacked\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Registry]
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".myp"; ValueData: ""
[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
; Filename: "{app}\resources\bin\dfcft8.exe"; Description: ""; Flags: nowait postinstall skipifsilent
[code]
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
begin
ExtractTemporaryFile('dfcft8.exe');
Exec(ExpandConstant('{tmp}\dfcft8.exe'), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
Log('InitializeSetup called');
Result := true
end;
这里有个疑问,ExtractTemporaryFile('dfcft8.exe') 路径
这里可没指定过 'dfcft8.exe' 文件位置,而且我明明是把它放在了 resources\bin\dfcft8.exe 下,难道会自动搜索?
测试一下猜想
为了测试我把用另一个 "electron-fiddle.exe" 安装包放在 resources 文件夹并且名称改为同样的 'dfcft8.exe' ,这样就有两个同名文件在不同文件夹下
resources\bin\'dfcft8.exe'
resources\'dfcft8.exe'
编译测试结果:

果然被改名为 'dfcft8.exe' 的 'electron-fiddle.exe' 被启动代替了东方财富的安装程序
官网我找不到资料,但测试后得到的结论是 ExtractTemporaryFile 会返回搜索到的第一个匹配文件
如果非要解压指定文件夹下的指定文件呢?
那么需要换种方法,像下面这样改:
[Files]
Source: "C:\Users\Administrator\Desktop\first-electron\release\0.0.0\win-unpacked\resources\bin\dfcft8.exe"; DestDir: "{tmp}\resources\bin"
[code]
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
begin
ExtractTemporaryFiles('{tmp}\resources\bin\dfcft8.exe')
Exec(ExpandConstant('{tmp}\resources\bin\dfcft8.exe'), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
Log('InitializeSetup called');
Result := true
end;
[Files] 节点指定 DestDir: "{tmp}\resources\bin"
[code] 节点内使用 ExtractTemporaryFiles('{tmp}\resources\bin\dfcft8.exe') 解压
并且 Exec 方法调用时也要传路径 ExpandConstant('{tmp}\resources\bin\dfcft8.exe')
编译测试一下

可以看到已经执行调用东方财富的安装程序
先别急着关掉,我们可以通过 log 输出的临时路径信息,找到对应的文件夹打开查看 C:\Users\ADMINI~1\AppData\Local\Temp\is-0467N.tmp
[17:15:15.953] Created temporary directory: C:\Users\ADMINI~1\AppData\Local\Temp\is-0467N.tmp

果然临时文件夹内文件夹结构如我们所指定的那样
该路径会在安装程序结束时自动删除
用 [code] 实现安装完成后执行 "dfcft8.exe" 可执行文件
之前是在 [Run] 节点下实现,其实也可以用 procedure DeinitializeSetup() 实现类似的功能
改动如下:
[code]
function InstallDfcf: Boolean;
var
ResultCode: Integer;
begin
if not Exec(ExpandConstant('{app}\resources\bin\dfcft8.exe'), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
Log('安装东方财富失败. Error code: ' + IntToStr(ResultCode));
end;
end;
procedure DeinitializeSetup();
begin
InstallDfcf;
end;
函数 DeinitializeSetup 就是安装结束时调用自定义函数 InstallDfcf
InstallDfcf 函数内部的 Exec 调用了 'dfcft8.exe'
还有更多..
Inno Setup 其实可定制化的功能还有很多,官网文档就仁者见仁智者见智了
全面详细学习 Inno Setup 没啥意义,用哪个功能直接了解这一块儿就行,就是学习各种配置
现在有 chatgpt,还记啥配置呢,不明白可以直接问它,chatgpt 真是事半功倍啊,反正我就是这么做的
我们该把时间用于更有意义的地方,比如摸鱼!
博客园: http://cnblogs.com/willian/
github: https://github.com/willian12345/
Electron App 安装包定制 -- Inno Setup 脚本 Pascal Scripting 初探的更多相关文章
- 制作部署安装包:Inno Setup
制作部署安装包:Inno Setup 前一篇尝试Office 2003 VSTO的开发.部署有提到用VS开发一个简单的VSTO程序.打包C/S程序,我首先想到的是VS里自带的Setup Project ...
- Inno Setup脚本语法大全
Inno Setup脚本语法大全 ResourceShare Bruce 11个月前 (10-28) 6136浏览 0评论 Inno Setup 是什么?Inno Setup 是一个免费的 Win ...
- 使用Inno SetUp脚本打包Winform程序
在开发桌面程序时,往往需要用到打包工具将程序打包为exe可执行文件. 之前在项目中用了下 InstallShield Limited Edition for Visual Studio 2015,它 ...
- INNO SETUP脚本向导创建的基本脚本
脚本范例分析:先来看看一段用INNO SETUP脚本向导创建的基本脚本的[Setup]段: [Setup] AppName=Premiere 6.5 汉化补丁-----------------(程 ...
- 以前编写的inno setup脚本,涵盖了自定义安装界面,调用dll等等应用 (转)
以前编写的inno setup脚本,涵盖了自定义安装界面,调用dll等等应用 (转) ; Script generated by the Inno Setup 脚本向导. ; SEE THE DOCU ...
- inno setup脚本,涵盖了自定义安装界面,调用dll等等应用
; Script generated by the Inno Setup 脚本向导. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETU ...
- Inno Setup 脚本
给你个我用的例子: Delphi/Pascal code ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 2 ...
- Inno Setup脚本
某天夜晚一场狂风暴雨,由于办公室座位旁的窗户没关,笔记本电脑泡了一夜水,无法开机,无奈送修,里面的大量资料也不知道会不会丢失. is的脚本只有重新写了,重新研究了一下检测程序是否正在运行的判断方法,另 ...
- Android App安装包瘦身计划
Android App安装包瘦身计划 Android App安装包体积优化: 理由, 指标和可以采用的方法. 本文内容归纳如下图: 为什么要安装包瘦身 安装包需要瘦身吗? 不需要吗? 安装包要瘦身的主 ...
- LNMP一键安装包 PHP自动升级脚本
LNMP一键安装包 PHP自动升级脚本 2011年03月15日 上午 | 作者:VPS侦探 前一段时间完成了lnmp一键安装包的PHP自动升级脚本,今天发布出来,如果想升级PHP版本的lnmp用户可以 ...
随机推荐
- 利用NGINX搭建部署直播流媒体服务器
直播如今是一个老生常谈的问题,怎么用于直播,大多数人只晓得,大佬某平台直播软件,点击开始即可直播.那么如何来搭建一个简易的直播平台呢?仅仅是有直播功能,没有涉及转码以及播放软件. 安装nginx以及r ...
- [ElasticSearch]修改开源安全组件Search Guard-6 用户密码
ES有很多的安全组件可用,例如: X-pack,Sarch Guard.但目前开源免费的,仅Search Guard. 1 前置条件 Elastic Search 6 服务安装成功,且成功运行. ES ...
- 随手记:lnmp 安装完 redis 后无法全局操作
说明redis-server不是全局命令,那么假如到全局即可 假设redis安装目录是:/usr/local/redis/bin/redis-cli ln -s /usr/local/redis/b ...
- 【SpringBoot2】 SpringBoot2核心技术 基础
写在前面 1 SpringBoot2核心技术 基础 1.1 Spring与SpringBoot SpringBoot是一个高层框架 1.2 项目创建 1.2.1 创建POM ①导入spring-boo ...
- .NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法
前言 前段时间有朋友问道一个这样的问题,.NET Core中如何通过Attribute的元数据信息来调用标记的对应方法.我第一时间想到的就是通过C#反射获取带有Custom Attribute标记的类 ...
- 100026. 【NOIP2017提高A组模拟7.7】图
题目大意: 给你n个点,每个点只有一条出路,请问每个点走了k步之后走过的权值和. 权值最小的边的权值. 考场想法: 考试时就先打了个暴力,然后发现一定会形成一个环,所以就想到了可以判环,然后 按照规律 ...
- 可视化大屏的终极解决方案居然这么简单,vue-autofit一行全搞定!
可视化大屏适配/自适应现状 可视化大屏的适配是一个老生常谈的话题了,现在其实不乏一些大佬开源的自适应插件.工具但是我为什么还要重复造轮子呢?因为目前市面上适配工具每一个都无法做到完美的效果,做出来的东 ...
- 【机器学习与深度学习理论要点】26.请列举AlexNet的特点
请列举AlexNet的特点 使用ReLU作为激活函数,并验证其效果在较深的网络超过了Sigmoid,成功解决了sigmoid在网络较深时梯度消失问题 使用dropout(丢弃学习)随机忽略一部分神经元 ...
- 基于pip的python包管理工具
以下是软件下载链接:https://mysecreat.lanzoub.com/i5yvf0swgtne 软件功能:可以对python包进行安装.卸载.升级.换源等操作,不用输入复杂命令 源码: im ...
- 聊一聊 Valgrind 监视非托管内存泄露和崩溃
一:背景 1. 讲故事 只要是程序总会出现各种莫名其妙的问题,比如:非托管内存泄露,程序崩溃,在 Windows 平台上一般用微软自家的官方工具 App Verifier 就可以洞察,那问题出在 Li ...