Inno Setup 安装包Windows服务
在开发服务端程序时,经常需要把程序以 Windows 服务 的方式安装到目标机器。Inno Setup 本身没有直接安装服务的标记,但可以通过 sc.exe 命令或 Pascal 脚本来实现,下面分别介绍两种方案。
方案一:使用sc.exe命令
sc.exe 是 Windows 自带的服务控制命令。通过 [Run] 段在安装完成后创建服务,通过 [UninstallRun] 段在卸载时停止并删除服务。
创建服务
1 |
|
在 StackOverflow 上大家普遍反馈,上面这种方式就能正常完成服务的安装与卸载,不需要额外处理。
卸载时停止并删除服务
1 |
|
卸载时必须先 stop 再 delete,顺序不能颠倒。
sc.exe create 常用参数说明
参考 Microsoft Learn - sc create:
| 参数 | 说明 |
|---|---|
type= {own|share|kernel|filesys|rec|interact} |
服务类型,默认 own(独立进程) |
start= {boot|system|auto|demand|disabled|delayed-auto} |
启动类型,默认 demand(手动);auto 为开机自启 |
error= {normal|severe|critical|ignore} |
服务启动失败时的错误级别,默认 normal |
binpath= <二进制路径> |
服务可执行文件路径,必填 |
group= <加载顺序组> |
服务所属的加载顺序组 |
depend= <依赖的服务> |
服务依赖,多个依赖用 / 分隔,如 depend= mpssvc |
obj= <账户名> |
服务运行账户,默认 LocalSystem |
displayname= <显示名称> |
在服务管理器中显示的名称 |
password= <密码> |
obj 指定账户的密码 |
注意:每个选项的等号必须紧跟选项名(
start=),等号与值之间必须有一个空格(start= auto)。省略空格会导致命令失败。
设置服务描述与故障恢复
创建服务后,还可以通过 sc 子命令设置服务描述和故障恢复策略:
1 |
|
注意
actions=中的时间单位是毫秒,reset=的单位是分钟(如86400分钟即 60 天,界面上以天显示)。
个别环境下sc failure配合runhidden标志可能不生效,若发现未生效可去掉runhidden([Run]段默认会等待命令执行完成)。
方案二:使用Pascal脚本完整控制服务
sc.exe 方式简单直接,但无法精细判断命令执行结果;升级覆盖安装时,若旧服务还在运行,直接 sc create 会因服务已存在而失败。此时可以使用 Pascal 脚本(SCM API)完整控制服务的检测、安装、启动、停止与删除。
升级时先停止旧服务
覆盖安装时,旧服务的 exe 文件正被占用,Inno Setup 会在复制文件前检查文件占用并弹出终止进程提示。更稳妥的做法是在 PrepareToInstall 事件中(文件占用检查之前)先停止旧服务:
1 |
|
若服务未停止(如处于停止挂起状态),可返回
NeedsRestart := True要求系统重启后继续安装。
使用SCM API服务库
需要更精细的控制(检测服务是否存在、是否在运行、启动/停止/删除服务等),可以引入 Luigi Sandon 的服务库脚本(services_unicode.iss),在 [Code] 段开头 #include 即可:
1 |
|
库中常用的函数:
ServiceExists、SimpleQueryService、SimpleCreateService、SimpleStartService、SimpleStopService、SimpleDeleteService。库文件建议放在脚本同目录下,与.iss文件一起维护。
远程服务器上的服务操作
需要操作远程机器上的服务时,sc 命令支持指定服务器名,或使用 Sysinternals 的 psservice 工具:
1 |
|
注意事项
- 创建/删除服务需要管理员权限,脚本中需设置
PrivilegesRequired=admin。 binPath中路径含空格时必须加引号,Inno Setup 参数中字面引号要用""转义(如上文的binPath= ""{app}\HelloWindowsService.exe"")。- 覆盖安装时,服务已存在会导致
sc create失败(错误码 1072/1073),建议结合PrepareToInstall停止服务或在[Code]中先删除旧服务。 - 如果服务程序本身支持自注册(如 .NET 服务通过
--install参数调用ManagedInstallerClass),也可在[Run]/[UninstallRun]中直接调用服务程序自身的安装/卸载参数,无需依赖sc.exe。
掘:奇葩史