最近在工作中使用NSIS脚本维护现有的软件安装包,使用NSIS制作安装包,简单快捷,对于任何一个有编程经验的程序员来说都是非常容易上手的工具之一,灵活强大,官方文档是非常好的学习资料,但是很多在实际应用过程中的坑并没有记录在册,故写一篇博客记录开发过程中遇到的坑和经验。
版本
NSIS Unicode 版本号?
下面总结遇到的坑和建议
使用插件
使用插件之前一定要搞清楚插件是不是支持Unicode版本,网上有很国内多资源平台提供NSIS插件合集的下载,并非官方网站正规渠道,插件合计的提供者有时忽略记录插件对应NSIS版本信息。我就遇到这样一个情况,下载NSIS插件之后在正常版本(非Unicode版)下使用,但是在Unicode版本下无效。此处不对Unicode与ANSI做详细的介绍,如果不清楚可以自己百度。
建议:通过官方网站提供插件地址下载所需的插件。
语法:行跳转
NSIS使用StrCmp比较两个字符串的大小
函数原型:
跳转在NSIS脚本是比较常见的一种逻辑判断结果验证方式,相比于标签的方式容易出错,代码维护过程中容易遗忘。比如像在某一个逻辑段中使用DetailPrint打印一条日志消息,添加1行造成之前的跳转目标行减少1行,稍不留神就会出现bug。
建议:1.使用跳转标签的方法代替goto跳转至某一行;2.使用???Logic.nsh???模块的${If}...${Else}...${endIf}
方式进行逻辑处理。
cmd指令
cmd传参注意事项
命令行传参是注意.exe的路径必须使用""括起来,否则根据cmd的语法遇到空格时自动截取参数,传递参数无效导致命令执行失败,例如安装目录在默认系统目录C:\Program Files (x86)
,传参时不使用双引号,会出现要执行命令。
常用的执行命令行指令有:ExecWait, nsExec:Exec
建议:推荐使用nsExec:Exec
,提供扩展参数。
sc指令操作服务
nsExec执行命令行指令虽然有/TIMEOUT=1000参数来设置超时时间,实际上sc指令在cmd中是一个异步指令,在执行sc stop ServiceName
后实际上是给windows的服务管理工具发送停止ServiceName
服务的消息,并立即返回。如果执行sc stop
之后立即执行删除ServiceName
服务的exe程序,实际上很多时候是无法删除的。
建议:每次执行sc指令操作服务后,使用Sleep 100
睡眠一段时间,确保服务操作已经完成后继续执行后续指令。
taskkill指令失效
taskkill作为windows 提供的结束应用程序指令用来杀死正在运行中的进程,在一些特定操作系统环境下会出现无效的情况(即使使用cmd调用也无法成功删除进程),使用nsExec调用taskkill时超时时间参数/TIMEOUT
一定不能设置时间过长。在工作中就遇到类似的情况,使用nsExec:Exec /TIMEOUT=60000 taskkill /F /IM test.exe
杀死进程时出现taskkill无效的情况,安装过程等待指令超时60s,进度条长时间停在一个位置,被认为是安装包“卡死”,实际是因为超时时间设置过长导致。
杀死指定名称的进程:taskkill /F /IM process_name.exe
解决方案:使用NSIS插件结束运行中的进程KillProcess;或自定义插件封装TerminateProcess
(windows API)结束进程。
根据安装日志卸载
实现脚本
官方提供日志内容删除安装的文件(包括释放文件、创建快捷方式),但是根据日志删除文件无法删除创建目录,删除目录需要自己实现。
同名目录升级安装
升级安装过程中,首先要卸载旧版本,考虑到新旧版本的兼容性问题,一般做法是检测到旧版本时调用卸载程序,卸载完成后执行安装脚本内容。
删除的调用过程无非是静默调用之前的卸载程序,
删除文件夹RMDIR
很多时候在编写脚本的过程中习惯使用RMDIR /r删除一个文件夹,有误/r参数差别很大,RMDIR只能删除非空文件夹,而/r参数则是删除文件夹及文件夹下的所有文件。故/r参数必须慎重使用,一旦出现传参失误,就会导致整个目录被波及。
工作中曾经有一个真实的“事故”。使用
RMDIR /r
删除安装过程中创建的快捷方式,一个bug出现传参时删除目录参数为空,导致开始菜单被清空,在用户的机器上出现上述结果,造成极大的影响。
建议:RMDIR慎用/r参数,必须保证参数传递正确。
文件重启后丢失(/REBOOT标记)
NSIS对于文件操作的函数Rename,Delete,RMDIR等
提供扩展参数/REBOOT,此标记应用于操作文件被占用无法删除、或者目录无法删除时被标记为重启删除。
在相同安装目录覆盖升级安装过程中会出现文件在卸载时被占用,并标记为/REBOOT状态,同名文件无法成功替换,本次安装完成后一切正常,但是用户重启机器后文件被删除,出现部分文件或应用缺少文件无法启动的“诡异”情况。
同步等待静默卸载
静默卸载函数原型:
同步等待静默卸载结果时必须添加_?=制定路径
参数,否则NSIS会创建临时的卸载程序副本到临时目录异步执行卸载过程,立即返回。
总结经验
版本比较
C++开发NSIS插件
根据NSIS安装目录下Example/Plugin目录提供的Demo,引用相关的静态库即可。
功能集锦
打开关闭日志(logset)
logset on/off 用于打开和关闭NSIS的默认日志输出功能。
打开日志后,DetailPrint输出的内容不仅会显示在默认安装界面的详细信息列表中,同时也会写入install.log文件;LogText只是输出日志。
参考资料
[1] NSIS学习笔记(二)-使用C++开发NSIS插件
http://blog.csdn.net/lee353086/article/details/46349157