八、卸载/回滚安装

安装过程中遇到问题不能再继续完成安装,那么我们应该把机器环境恢复到安装前的状态,这就需要回滚安装,每个安装程序都有它自己的安装步骤和组件,所以要根据实际情况来设置标识来标注安装了哪些组件或操作,在回滚时才可以依此来恢复,另外我们的回滚程序要写在哪里才会被正确的调用;还有卸载安装包括哪些页面,需要怎么做等等;开始之前我们先介绍下回调函数。

回调函数

一般函数名以 . 开头的作为回调函数保留,这些函数将会由安装/卸载程序在安装/卸载时需要某些用途时调用。一些主要的安装/卸载回调函数如下:

  • .onGUIInit/un.onGUIInit该回调将会在第一个页面被载入并且显示安装/卸载程序对话框前被调用,允许你来调整用户界面。 

  • .onInit/un.onInit该回调将会在当安装/卸载程序接近完成初始化时调用。如果 .onInit/ un.onInit 函数调用了Abort,则安装/卸载程序立即退出。

  • .onInstFailed/un.onUninstFailed该回调函数当在安装/卸载失败后用户点击“取消”按钮时被调用

  • .onInstSuccess/un.onUninstSuccess该回调当安装/卸载成功且正当安装/卸载窗口关闭前(如果自动关闭被设为 false 时可能在用户点击“关闭”之后)调用.

  • .onGUIEnd/un.onGUIEnd该回调正当安装/卸载程序窗口关闭之后被调用。需要时用来释放任何与用户界面有关的插件。

安装回滚

考虑到在安装失败时只恢复已经安装的组件或操作,所以需要根据实际情况来标识安装了哪些组件或操作。这里我们使用注册表来保存这些标识,并在回滚中判断标识要执行相应的指令。

以下示例保存数据库是否创建的标识"DBCreated",写入到注册表"Software\Microsoft\Windows\CurrentVersion\App Paths\ADWebManager.exe": 

!define DB_Created_RegKey "DBCreated"
!define PRODUCT_NAME "ADWebManager"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe" Section "数据库服务器配置" SEC04" ; 省略”连接SQL Server数据库、查询数据库是否存在“代码 ${If} $0 == 0 ; 数据库未创建 ; 省略”创建数据库和初始化数据库“代码 WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "${DB_Created_RegKey}" "True" ${Else} WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "${DB_Created_RegKey}" "False" ${EndIf}   ; 省略代码 SectionEnd

 

当注册表项标识"DBCreated"值为“True"时,回滚时要删除创建的数据库,示例如下所示:

Function Rollback
    ; 省略代码

    ; 恢复数据库设置
    DetailPrint "恢复数据库设置"
    ReadRegStr $0 HKLM "${PRODUCT_DIR_REGKEY}" "${DB_Created_RegKey}"
    ${If} $0 == True ; 删除数据库
             ; 省略“删除数据库”代码
        ${EndIf}
  ; 省略代码
 FunctionEnd

安装过程中,当安装或配置组件信息时出错则使用指令Abort取消安装,停止执行脚本,这时我们可以在回调函数.onInstFailed执行回滚操作,如下示例:

Function .onInstFailed
  Call Rollback
FunctionEnd

安装卸载

安装程序安装成功完成后,需要生成卸载程序并生成相应的快捷方式,示例如下:

 

Section -Post
        ; 写入卸载程序
        WriteUninstaller "$INSTDIR\ADWebManager\Uninstall.exe"
        ; 创建桌面快捷方式文件夹
        CreateDirectory "$DESKTOP\${PRODUCT_NAME}"
        CreateShortCut  "$DESKTOP\${PRODUCT_NAME}\Website.lnk" "https://www.baidu.com"
        CreateShortCut  "$DESKTOP\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\ADWebManager\Uninstall.exe"
        ; 省略其他代码
SectionEnd

 

NSIS内置的卸载页面有以下(参见NSIS用户手册):

UninstPage uninstConfirm

UninstPage instfiles

现代用户界面有以下内置页面(参见NSIS Modern User Interface):

MUI_UNPAGE_WELCOME
MUI_UNPAGE_CONFIRM
MUI_UNPAGE_LICENSE textfile
MUI_UNPAGE_COMPONENTS
MUI_UNPAGE_DIRECTORY
MUI_UNPAGE_INSTFILES
MUI_UNPAGE_FINISH

以下是我们的卸载程序页面示例:

; 卸载程序页面开始----------------------
; 欢迎页面
!insertmacro MUI_UNPAGE_WELCOME
; 卸载安装记录页面
!insertmacro MUI_UNPAGE_INSTFILES
; 完成页面
!insertmacro MUI_UNPAGE_FINISH
; 卸载程序页面结束----------------------

在卸载页面开始前我们希望有提示,让用户确认一下是否卸载,如下:

Function un.onInit
  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "你确实要完全移除 $(^Name) ,其及所有的组件?" IDYES + 2
  Abort
FunctionEnd

或者也可以在插入确认页面:

!insertmacro MUI_UNPAGE_CONFIRM

我们知道如果一个区段名为“Uninstall”或以“un.”为前缀,那么它就是一个卸载程序区段;函数名以 un. 开头的函数将会被创建在卸载程序里,因此,普通安装区段和函数不能调用卸载函数,而卸载区段和卸载函数也不能调用普通安装程序的函数。所以我们在卸载程序区段“Uninstall”调用卸载程序,由于卸载和安装失败回滚的代码类似,我们可以只写一份,但卸载区段调用的函数必须以“un.”为前缀,所以我们可以改进一下Rollback函数,使它既可以被安装程序调用也可以被卸载程序调用,如下:

Section Uninstall
       Call un.Rollback
SectionEnd
!macro MYMACRO un
Function ${un}Rollback
  ; 省略代码
   ; 恢复数据库设置
   DetailPrint "恢复数据库设置"
   ReadRegStr $0 HKLM "${PRODUCT_DIR_REGKEY}" "${DB_Created_RegKey}"
   ${If} $0 == True ; 删除数据库
       ; 省略“删除数据库”代码
   ${EndIf}
  ; 省略代码
FunctionEnd
!macroend
!insertmacro MYMACRO "" 
!insertmacro MYMACRO "un."

 卸载成功完成后我们希望有提示信息,可以在回调函数中提示,如下:

Function un.onUninstSuccess
        HideWindow
        MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从你的计算机移除。"
FunctionEnd

至此,NSIS安装程序的制作所有章节已经介绍完毕。

posted @ 2016-05-23 19:12  所以呢  阅读(2554)  评论(1编辑  收藏  举报