May
5
Inno Setup制作的安装程序在安装时能记录安装内容,生成unins000.dat之类的文件,卸载时直接调用它。这样可以避免卸载时误删文件。
NSIS的卸载段一般是手写,如果安装程序包含的文件很多,一般就直接删除整个安装目录,或者逐个删除子目录,再逐个删除安装目录下的各个文件。这样存在误删除文件的危险性。比如如果用户将文件存放在驱动器根目录下,如果整个删除安装目录,那就将一个驱动器的东西都删光了!况且更新维护脚本的同时需要考虑到卸载段的更改,个人觉得是比较麻烦。
这也是我不太喜欢NSIS的原因之一。(还有另一个重要原因是NSIS制作的安装程序在安装时如果“取消”了安装,将不能回复到安装前的状态,而INNO可以哦!这和本文无关~)
其实NSIS也提供了LOG功能,只是在正式发行版本里没有开启,必须使用它的特殊编译器。而这个Special Build官方早就为你想到了,在NSIS的全部文件下载页面里就有:http://sourceforge.net/project/showfiles.php?group_id=22049
其中每个版本出来,都有个LOG.zip。 如 nsis-2.37-log.zip ,这就是2.37版的开启LOG功能的版本。安装了正式发行的版本,再解包这个LOG的ZIP文件到安装目录,覆盖掉原文件。
如何使用这个功能?
HM VNISEdit 的向导可以自动生成“安全卸载”的代码,就是以下的内容:
1、在普通安装脚本前添加库
2、; 激活安装日志记录,该日志文件将会作为卸载文件的依据(注意,本区段必须放置在所有区段之前)
Section "-LogSetOn"
LogSet on
SectionEnd
3、
/******************************
* 以下是安装程序的卸载部分 *
******************************/
; 根据安装日志卸载文件的调用宏
!macro DelFileByLog LogFile
ifFileExists `${LogFile}` 0 +4
Push `${LogFile}`
Call un.DelFileByLog
Delete `${LogFile}`
!macroend
Section Uninstall
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
Delete "$INSTDIR\${PRODUCT_NAME}.url"
; 调用宏只根据安装日志卸载安装程序自己安装过的文件
!insertmacro DelFileByLog "$INSTDIR\install.log"
; 清除安装程序创建的且在卸载时可能为空的子目录,对于递归添加的文件目录,请由最内层的子目录开始清除(注意,不要带 /r 参数,否则会失去 DelFileByLog 的意义)
RMDir "$SMPROGRAMS\$ICONS_GROUP"
SectionEnd
#-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--#
; 以下是卸载程序通过安装日志卸载文件的专用函数,请不要随意修改
Function un.DelFileByLog
Exch $R0
Push $R1
Push $R2
Push $R3
FileOpen $R0 $R0 r
${Do}
FileRead $R0 $R1
${IfThen} $R1 == `` ${|} ${ExitDo} ${|}
StrCpy $R1 $R1 -2
StrCpy $R2 $R1 11
StrCpy $R3 $R1 20
${If} $R2 == "File: wrote"
${OrIf} $R2 == "File: skipp"
${OrIf} $R3 == "CreateShortCut: out:"
${OrIf} $R3 == "created uninstaller:"
Push $R1
Push `"`
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
IntOp $R2 $R2 + 1
StrCpy $R3 $R1 "" $R2
Push $R3
Push `"`
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
StrCpy $R3 $R3 $R2
Delete /REBOOTOK $R3
${EndIf}
${EndIf}
${EndIf}
StrCpy $R2 $R1 7
${If} $R2 == "Rename:"
Push $R1
Push "->"
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
IntOp $R2 $R2 + 2
StrCpy $R3 $R1 "" $R2
Delete /REBOOTOK $R3
${EndIf}
${EndIf}
${Loop}
FileClose $R0
Pop $R3
Pop $R2
Pop $R1
Pop $R0
FunctionEnd
Function un.DelFileByLog.StrLoc
Exch $R0
Exch
Exch $R1
Push $R2
Push $R3
Push $R4
Push $R5
StrLen $R2 $R0
StrLen $R3 $R1
StrCpy $R4 0
${Do}
StrCpy $R5 $R1 $R2 $R4
${If} $R5 == $R0
${OrIf} $R4 = $R3
${ExitDo}
${EndIf}
IntOp $R4 $R4 + 1
${Loop}
${If} $R4 = $R3
StrCpy $R0 ""
${Else}
StrCpy $R0 $R4
${EndIf}
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
按照上面的方法,就可以编译脚本了。
NSIS就是这么麻烦。生成的install.log没有经过任何的加密,用记事本就完全可以看到做了什么东西。
【注意!】上面的是一个非常简易的方法,生成的log保存在$INSTDIR\install.log文件中,该文件的名字不能改!如果你想把log保存到其它文件,必需自己从http://nsis.sourceforge.net/Development_Files下载NSIS的源代码,然后修改、重新编译! 具体操作就留给你自己去想了。
NSIS的卸载段一般是手写,如果安装程序包含的文件很多,一般就直接删除整个安装目录,或者逐个删除子目录,再逐个删除安装目录下的各个文件。这样存在误删除文件的危险性。比如如果用户将文件存放在驱动器根目录下,如果整个删除安装目录,那就将一个驱动器的东西都删光了!况且更新维护脚本的同时需要考虑到卸载段的更改,个人觉得是比较麻烦。
这也是我不太喜欢NSIS的原因之一。(还有另一个重要原因是NSIS制作的安装程序在安装时如果“取消”了安装,将不能回复到安装前的状态,而INNO可以哦!这和本文无关~)其实NSIS也提供了LOG功能,只是在正式发行版本里没有开启,必须使用它的特殊编译器。而这个Special Build官方早就为你想到了,在NSIS的全部文件下载页面里就有:http://sourceforge.net/project/showfiles.php?group_id=22049
其中每个版本出来,都有个LOG.zip。 如 nsis-2.37-log.zip ,这就是2.37版的开启LOG功能的版本。安装了正式发行的版本,再解包这个LOG的ZIP文件到安装目录,覆盖掉原文件。
如何使用这个功能?
HM VNISEdit 的向导可以自动生成“安全卸载”的代码,就是以下的内容:
1、在普通安装脚本前添加库
!include "LogicLib.nsh"
2、; 激活安装日志记录,该日志文件将会作为卸载文件的依据(注意,本区段必须放置在所有区段之前)
Section "-LogSetOn"
LogSet on
SectionEnd
3、
/******************************
* 以下是安装程序的卸载部分 *
******************************/
; 根据安装日志卸载文件的调用宏
!macro DelFileByLog LogFile
ifFileExists `${LogFile}` 0 +4
Push `${LogFile}`
Call un.DelFileByLog
Delete `${LogFile}`
!macroend
Section Uninstall
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
Delete "$INSTDIR\${PRODUCT_NAME}.url"
; 调用宏只根据安装日志卸载安装程序自己安装过的文件
!insertmacro DelFileByLog "$INSTDIR\install.log"
; 清除安装程序创建的且在卸载时可能为空的子目录,对于递归添加的文件目录,请由最内层的子目录开始清除(注意,不要带 /r 参数,否则会失去 DelFileByLog 的意义)
RMDir "$SMPROGRAMS\$ICONS_GROUP"
SectionEnd
#-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--#
; 以下是卸载程序通过安装日志卸载文件的专用函数,请不要随意修改
Function un.DelFileByLog
Exch $R0
Push $R1
Push $R2
Push $R3
FileOpen $R0 $R0 r
${Do}
FileRead $R0 $R1
${IfThen} $R1 == `` ${|} ${ExitDo} ${|}
StrCpy $R1 $R1 -2
StrCpy $R2 $R1 11
StrCpy $R3 $R1 20
${If} $R2 == "File: wrote"
${OrIf} $R2 == "File: skipp"
${OrIf} $R3 == "CreateShortCut: out:"
${OrIf} $R3 == "created uninstaller:"
Push $R1
Push `"`
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
IntOp $R2 $R2 + 1
StrCpy $R3 $R1 "" $R2
Push $R3
Push `"`
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
StrCpy $R3 $R3 $R2
Delete /REBOOTOK $R3
${EndIf}
${EndIf}
${EndIf}
StrCpy $R2 $R1 7
${If} $R2 == "Rename:"
Push $R1
Push "->"
Call un.DelFileByLog.StrLoc
Pop $R2
${If} $R2 != ""
IntOp $R2 $R2 + 2
StrCpy $R3 $R1 "" $R2
Delete /REBOOTOK $R3
${EndIf}
${EndIf}
${Loop}
FileClose $R0
Pop $R3
Pop $R2
Pop $R1
Pop $R0
FunctionEnd
Function un.DelFileByLog.StrLoc
Exch $R0
Exch
Exch $R1
Push $R2
Push $R3
Push $R4
Push $R5
StrLen $R2 $R0
StrLen $R3 $R1
StrCpy $R4 0
${Do}
StrCpy $R5 $R1 $R2 $R4
${If} $R5 == $R0
${OrIf} $R4 = $R3
${ExitDo}
${EndIf}
IntOp $R4 $R4 + 1
${Loop}
${If} $R4 = $R3
StrCpy $R0 ""
${Else}
StrCpy $R0 $R4
${EndIf}
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
按照上面的方法,就可以编译脚本了。
NSIS就是这么麻烦。生成的install.log没有经过任何的加密,用记事本就完全可以看到做了什么东西。【注意!】上面的是一个非常简易的方法,生成的log保存在$INSTDIR\install.log文件中,该文件的名字不能改!如果你想把log保存到其它文件,必需自己从http://nsis.sourceforge.net/Development_Files下载NSIS的源代码,然后修改、重新编译! 具体操作就留给你自己去想了。



