从 Linux 或 Mac 签署 NSIS 卸载程序
Signing NSIS Uninstaller from Linux or Mac
我正在将我们的 NSI 安装程序移植到 Linux 和 Mac 而不是 Windows 以更好地与我们的 Maven 构建系统集成。
我们需要签署我们的安装程序和卸载程序。这是按照 http://nsis.sourceforge.net/Signing_an_Uninstaller 的建议完成的,但我刚刚意识到它试图 运行 tempinstaller 强制它生成 uninstaller.exe 然后可以签名。
显然这个技巧在 *Nix 系统上效果不佳,这使得这部分过程不可移植。
有没有人有更好的解决办法。我不是 NSIS 的专家,想知道是否有一种聪明的方法来获取 uninstall.exe 以便对其进行签名?
我认为没有真正的解决方案。
安装程序和卸载程序使用相同的 exe 代码,并且在启动时只检查一个标志(FH_FLAGS_UNINSTALL
in firstheader
)以查看它是否是卸载程序。仅仅翻转这个位是不够的,程序将无法通过 CRC 检查,即使你绕过卸载程序数据被压缩,所以你必须将它解压缩到文件中的正确位置。要真正做到这一点,您必须编写一个自定义工具。如果您搜索 EW_WRITEUNINSTALLER
.
,您可以在 exec.c 的 NSIS 源中看到此操作
We need to sign our installer and uninstaller. This was done as suggested at http://nsis.sourceforge.net/Signing_an_Uninstaller, but I just realized that it tries to run the tempinstaller to force it to produce the uninstaller.exe which can then be signed. [...] this trick doesn't work too well on *Nix systems and make this part of the process non-portable.
如果您利用存根安装程序进行卸载操作(无负载),这似乎是可能的。
它将从 $TEMP
文件夹中生成一个 uninstall.exe
进程,然后可以删除 $INSTDIR
。
此脚本将创建一个存根(卸载)安装程序,然后可以对其进行 Authenticode 签名。它将在 Windows、MacOS 和 Linux.
上编译
注意事项:
- 您必须手动将其捆绑到安装程序中(简单)
- 您必须管理自己的卸载注册表项(琐碎)
- 外观可能与 NSIS 的卸载程序默认值不匹配
- 您会看到安装程序打开了两次(第一次来自
$INSTDIR
,第二次来自 $TEMP
)。这是一个 child 进程,允许 uninstall.exe
删除自身,类似于 NSIS does it in the Section "Uninstall"
.
- 您将需要一个辅助
.nsi
脚本专门用于卸载操作,如果您的 install/uninstall 部分之间有很多共享逻辑,这会很麻烦。
- 更糟糕的是,您必须避免
"Uninstall"
部分标题,因为在生成字节码时您将陷入与 OP 相同的问题.
- 当从
$TEMP
中显式 运行 时,某些相关文件逻辑将不正确。该示例分别将它们作为 $DELETE_DIR
、$DELETE_EXE
传回。
代码:
!include MUI2.nsh
!include x64.nsh
!include LogicLib.nsh
!include FileFunc.nsh
!include WinMessages.nsh
!define MUI_PRODUCT "My App"
!define MUI_VERSION "1.0.0"
; Masquerade the title
!define MUI_PAGE_HEADER_TEXT "Uninstall My App"
!define MUI_PAGE_HEADER_SUBTEXT "Remove My App from your computer"
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation Complete"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "Uninstall was completed successfully."
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro GetParameters
RequestExecutionLevel admin
CRCCheck On
OutFile "uninstall.exe"
Name "Uninstall"
Var /GLOBAL RESPAWN
Var /GLOBAL DELETE_DIR
Var /GLOBAL DELETE_EXE
Section
; Masquerade as uninstall
SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:Uninstall"
${GetParameters} [=10=]
${GetOptions} "[=10=]" "/RESPAWN=" $RESPAWN
${GetOptions} "[=10=]" "/DELETE_DIR=" $DELETE_DIR
${GetOptions} "[=10=]" "/DELETE_EXE=" $DELETE_EXE
${If} $RESPAWN != ""
; We're running from $TEMP; Perform the uninstall
!define yay "We're running from $EXEPATH, yay, we can remove the install directory!$\n$\n"
!define myvars "$\tRESPAWN$\t$RESPAWN$\n$\tDELETE_EXE$\t$DELETE_EXE$\n$\tDELETE_DIR$\t$DELETE_DIR"
MessageBox MB_OK "${yay}${myvars}"
; Your uninstall code goes here
; RMDir /r $DELETE_DIR\*.*
; Delete "$DESKTOP${MUI_PRODUCT}.lnk"
; Delete "$SMPROGRAMS${MUI_PRODUCT}\*.*"
; RmDir "$SMPROGRAMS${MUI_PRODUCT}"
; Delete Uninstaller And Unistall Registry Entries
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE${MUI_PRODUCT}"
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall${MUI_PRODUCT}"
; Remove the old version of ourself
ClearErrors
Delete $DELETE_EXE
IfErrors 0 +3
MessageBox MB_OK "File could NOT be deleted: $DELETE_EXE"
Goto +2
MessageBox MB_OK "File was successfully deleted: $DELETE_EXE"
; Remove ourself from $TEMP after reboot
Delete /REBOOTOK $EXEPATH
; ${If} ${RunningX64}
; ${EnableX64FSRedirection}
; ${EndIf}
SetDetailsPrint textonly
DetailPrint "Completed"
${Else}
; We're NOT running from $TEMP, copy to temp and respawn ourself
GetTempFileName [=10=]
CopyFiles "$EXEPATH" "[=10=]"
Exec '"[=10=]" /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"'
Quit
${EndIf}
SectionEnd
Function .onInit
; ${If} ${RunningX64}
; SetRegView 64
; ${DisableX64FSRedirection}
; ${EndIf}
FunctionEnd
我正在将我们的 NSI 安装程序移植到 Linux 和 Mac 而不是 Windows 以更好地与我们的 Maven 构建系统集成。
我们需要签署我们的安装程序和卸载程序。这是按照 http://nsis.sourceforge.net/Signing_an_Uninstaller 的建议完成的,但我刚刚意识到它试图 运行 tempinstaller 强制它生成 uninstaller.exe 然后可以签名。
显然这个技巧在 *Nix 系统上效果不佳,这使得这部分过程不可移植。
有没有人有更好的解决办法。我不是 NSIS 的专家,想知道是否有一种聪明的方法来获取 uninstall.exe 以便对其进行签名?
我认为没有真正的解决方案。
安装程序和卸载程序使用相同的 exe 代码,并且在启动时只检查一个标志(FH_FLAGS_UNINSTALL
in firstheader
)以查看它是否是卸载程序。仅仅翻转这个位是不够的,程序将无法通过 CRC 检查,即使你绕过卸载程序数据被压缩,所以你必须将它解压缩到文件中的正确位置。要真正做到这一点,您必须编写一个自定义工具。如果您搜索 EW_WRITEUNINSTALLER
.
We need to sign our installer and uninstaller. This was done as suggested at http://nsis.sourceforge.net/Signing_an_Uninstaller, but I just realized that it tries to run the tempinstaller to force it to produce the uninstaller.exe which can then be signed. [...] this trick doesn't work too well on *Nix systems and make this part of the process non-portable.
如果您利用存根安装程序进行卸载操作(无负载),这似乎是可能的。
它将从 $TEMP
文件夹中生成一个 uninstall.exe
进程,然后可以删除 $INSTDIR
。
此脚本将创建一个存根(卸载)安装程序,然后可以对其进行 Authenticode 签名。它将在 Windows、MacOS 和 Linux.
上编译注意事项:
- 您必须手动将其捆绑到安装程序中(简单)
- 您必须管理自己的卸载注册表项(琐碎)
- 外观可能与 NSIS 的卸载程序默认值不匹配
- 您会看到安装程序打开了两次(第一次来自
$INSTDIR
,第二次来自$TEMP
)。这是一个 child 进程,允许uninstall.exe
删除自身,类似于 NSIS does it in theSection "Uninstall"
. - 您将需要一个辅助
.nsi
脚本专门用于卸载操作,如果您的 install/uninstall 部分之间有很多共享逻辑,这会很麻烦。- 更糟糕的是,您必须避免
"Uninstall"
部分标题,因为在生成字节码时您将陷入与 OP 相同的问题.
- 更糟糕的是,您必须避免
- 当从
$TEMP
中显式 运行 时,某些相关文件逻辑将不正确。该示例分别将它们作为$DELETE_DIR
、$DELETE_EXE
传回。
代码:
!include MUI2.nsh
!include x64.nsh
!include LogicLib.nsh
!include FileFunc.nsh
!include WinMessages.nsh
!define MUI_PRODUCT "My App"
!define MUI_VERSION "1.0.0"
; Masquerade the title
!define MUI_PAGE_HEADER_TEXT "Uninstall My App"
!define MUI_PAGE_HEADER_SUBTEXT "Remove My App from your computer"
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation Complete"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "Uninstall was completed successfully."
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro GetParameters
RequestExecutionLevel admin
CRCCheck On
OutFile "uninstall.exe"
Name "Uninstall"
Var /GLOBAL RESPAWN
Var /GLOBAL DELETE_DIR
Var /GLOBAL DELETE_EXE
Section
; Masquerade as uninstall
SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:Uninstall"
${GetParameters} [=10=]
${GetOptions} "[=10=]" "/RESPAWN=" $RESPAWN
${GetOptions} "[=10=]" "/DELETE_DIR=" $DELETE_DIR
${GetOptions} "[=10=]" "/DELETE_EXE=" $DELETE_EXE
${If} $RESPAWN != ""
; We're running from $TEMP; Perform the uninstall
!define yay "We're running from $EXEPATH, yay, we can remove the install directory!$\n$\n"
!define myvars "$\tRESPAWN$\t$RESPAWN$\n$\tDELETE_EXE$\t$DELETE_EXE$\n$\tDELETE_DIR$\t$DELETE_DIR"
MessageBox MB_OK "${yay}${myvars}"
; Your uninstall code goes here
; RMDir /r $DELETE_DIR\*.*
; Delete "$DESKTOP${MUI_PRODUCT}.lnk"
; Delete "$SMPROGRAMS${MUI_PRODUCT}\*.*"
; RmDir "$SMPROGRAMS${MUI_PRODUCT}"
; Delete Uninstaller And Unistall Registry Entries
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE${MUI_PRODUCT}"
; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall${MUI_PRODUCT}"
; Remove the old version of ourself
ClearErrors
Delete $DELETE_EXE
IfErrors 0 +3
MessageBox MB_OK "File could NOT be deleted: $DELETE_EXE"
Goto +2
MessageBox MB_OK "File was successfully deleted: $DELETE_EXE"
; Remove ourself from $TEMP after reboot
Delete /REBOOTOK $EXEPATH
; ${If} ${RunningX64}
; ${EnableX64FSRedirection}
; ${EndIf}
SetDetailsPrint textonly
DetailPrint "Completed"
${Else}
; We're NOT running from $TEMP, copy to temp and respawn ourself
GetTempFileName [=10=]
CopyFiles "$EXEPATH" "[=10=]"
Exec '"[=10=]" /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"'
Quit
${EndIf}
SectionEnd
Function .onInit
; ${If} ${RunningX64}
; SetRegView 64
; ${DisableX64FSRedirection}
; ${EndIf}
FunctionEnd