开发工具教程工具NSIS打包保姆级教程(含后台服务注册)
Aurorp1gNSIS 打包保姆级教程(含守护进程注册与系统痕迹清理)
前言
很久没有用 NSIS 来打包安装程序了,导致我忘了如何使用(原先笔者以为之前已经写过 NSIS 相关教程,但那时候只写过某编译器的教程),所以记录下保姆级的教程,并补充近期踩坑的「排雷指南」。
内容
必要条件
安装 NSIS v3.08 版本,这里我下的是中文版,学习之初方便查看帮助文档。
感谢作者翻译!!!

具体操作
基础向导流程
- 点击 VNISEdit,进入脚本编写界面
- 文件 ==> 新建脚本:向导 ==> 进入向导界面,根据向导提示填写内容


- 图标与命名:可以更改为自己的图标(否则是 NSIS 的默认图标),安装程序文件名也能自定义(默认为 Setup)。建议在此处完成「品牌标识设定」,避免后续手动修改脚本。

- 授权文件一般用不着,除非要定制化安装界面,我现在是选择直接跳过。如无需授权,直接删除路径即可。


文件组织策略
- 到这一步,默认会有两个文件,直接删除它们,开始填充自己打包需要的文件。
- 左边 MainSection 表示主节点。如果安装程序不包含「守护进程注册」(后台服务)之类操作,使用默认即可。

- 找到需要打包的文件,将其添加进来(如某编译器直接找 Release 目录)。
- 如需打包「用户配置记忆库」(数据库/配置文件),按下图设置
SetOverwrite off,防止后续更新覆盖用户数据。

守护进程注册(后台服务)
如需打包「后台守护模块」(Windows Service):
- 新建 Section 命名为
ServiceSection(或「系统服务单元」) - 放入服务可执行文件,目的目录建议命名为
Service(或「系统服务目录」)


- 程序一般默认为前台程序,按下图设置快捷方式:



- 点击完成保存脚本。如需「守护进程注册」,在
ServiceSection 后追加以下脚本(使用「系统控制工具」 sc.exe 进行服务契约缔结):
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| IfFileExists "$INSTDIR\系统服务目录\${PRODUCT_SERVICEEXE}" +3 0 MessageBox MB_ICONSTOP "守护模块未找到:$\r$\n$INSTDIR\系统服务目录\${PRODUCT_SERVICEEXE}" Abort
DetailPrint "正在缔结系统守护契约..." nsExec::ExecToStack '"$SYSDIR\sc.exe" create "${PRODUCT_SERVICENAME}" binPath= "\"$INSTDIR\系统服务目录\${PRODUCT_SERVICEEXE}\"" start= auto DisplayName= "${PRODUCT_SERVICENAME}"' Pop $R0 Pop $R1
${If} $R0 != 0 DetailPrint "主方案受阻,尝试备用契约缔结... (状态码: $R0)" nsExec::ExecToStack '"$SYSDIR\cmd.exe" /C "sc create ${PRODUCT_SERVICENAME} binPath= \"$INSTDIR\系统服务目录\${PRODUCT_SERVICEEXE}\" start= auto DisplayName= \"${PRODUCT_SERVICENAME}\" "' Pop $R0 Pop $R1 ${EndIf}
${If} $R0 != 0 MessageBox MB_ICONSTOP "守护契约缔结失败! $\r$\n状态码: $R0 $\r$\n详细信息: $\r$\n$R1" StrCpy $0 "$TEMP\ServiceInstall.log" FileOpen $1 $0 w FileWrite $1 "缔结命令: $\r$\n$SYSDIR\sc.exe create ${PRODUCT_SERVICENAME} binPath= \"$INSTDIR\系统服务目录\${PRODUCT_SERVICEEXE}\" $\r$\n" FileWrite $1 "返回状态: $R0 $\r$\n" FileWrite $1 "详细信息: $\r$\n$R1" FileClose $1 ExecShell "open" "$TEMP" Abort ${EndIf}
DetailPrint "守护契约缔结成功"
DetailPrint "正在唤醒守护模块..." nsExec::ExecToLog "net start ${PRODUCT_SERVICENAME}" Pop $R0 ${If} $R0 != 0 MessageBox MB_ICONSTOP "守护模块唤醒失败,请手动启动 (状态码: $R0)" ${EndIf}
|
卸载阶段(含系统痕迹清理)
找到 Uninstall 节点(「解除安装」章节),追加以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
DetailPrint "正在执行文件释放术..." nsExec::ExecToStack '"taskkill" /F /IM "${PRODUCT_EXE_NAME}" /T' Pop $R0
DetailPrint "正在安抚守护模块..." nsExec::ExecToStack '"$SYSDIR\cmd.exe" /C "net stop ${PRODUCT_SERVICENAME}"' DetailPrint "正在解除守护契约..." nsExec::ExecToStack '"$SYSDIR\cmd.exe" /C "sc delete ${PRODUCT_SERVICENAME}"' Sleep 3000
RMDir /r "$INSTDIR\系统服务目录" RMDir /r "$INSTDIR"
|
进阶排障手册(踩坑记录)
基于近期实战,补充以下「边缘场景处置方案」:
1. 静默构建指令(自动化编译)
若需集成到 CI/CD 或脚本自动构建,避免 GUI 弹窗干扰:
1 2 3 4 5
| makensis /V3 your_script.nsi
Start-Process -FilePath "makensis" -ArgumentList "/V3","your_script.nsi" -WindowStyle Hidden -Wait
|
2. 文件释放术进阶(解决”程序自锁”与衍生实例)
当主程序包含「嵌入式浏览核心」(Chromium 类)时,卸载常因子进程残留失败。需在卸载前执行「全族进程回收」:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| !macro TerminateTree processName DetailPrint "正在回收运行实例: ${processName}" nsExec::ExecToStack '"taskkill" /F /IM "${processName}" /T' Pop $R0 Sleep 1000 !macroend
Section "Uninstall" !insertmacro TerminateTree "YourApp.exe" !insertmacro TerminateTree "YourAppHelper.exe" !insertmacro TerminateTree "chrome.exe" System::Call 'kernel32::FlushFileBuffers(i -1)' SectionEnd
|
3. 系统痕迹深度清理(注册表残留)
若程序设置了「自启动印记」(注册表 Run 键),卸载时需擦除痕迹:
1 2 3 4 5 6
| DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}" DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}"
DeleteRegKey HKCU "Software\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
|
注意:HKCU 表示「当前用户配置域」,HKLM 表示「本地机器配置域」,需根据软件安装范围选择。
4. 品牌标识自定义(图标与命名完全控制)
若对向导生成的图标/名称不满意,可在脚本头部手动指定「视觉标识」和「产物命名」:
1 2 3 4 5 6 7 8 9
| !define MUI_ICON "你的图标.ico" !define MUI_UNICON "你的卸载图标.ico"
OutFile "你的软件名-版本号-Installer.exe"
UninstallExeName "你的软件名-Uninstall.exe"
|
效果展示
实际安装图片

实际卸载图片
- 卸载时自动执行文件释放、停止并删除服务、清理系统痕迹
