Files

281 lines
11 KiB
NSIS

; Ant Browser NSIS Installer Script
; Usage: makensis /DVERSION=1.3.0 /DSTAGINGDIR=C:\path\to\staging installer.nsi
Unicode True
!ifndef VERSION
!define VERSION "1.3.0"
!endif
!ifndef STAGINGDIR
!define STAGINGDIR "..\publish\staging"
!endif
!define PRODUCT_NAME "Ant Browser"
!define PRODUCT_EXE "ant-chrome.exe"
!define PRODUCT_ICON "AntBrowser.ico"
!define UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\AntBrowser"
!define INSTALL_DIR "$PROGRAMFILES64\Ant Browser"
!define POWERSHELL_EXE "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe"
!include "MUI2.nsh"
!include "LogicLib.nsh"
!macro WriteCloseProcessScript HANDLE
FileWrite ${HANDLE} "param([string]$$InstallDir, [string]$$ExcludePath)$\r$\n"
FileWrite ${HANDLE} "$$ErrorActionPreference = 'SilentlyContinue'$\r$\n"
FileWrite ${HANDLE} "if ([string]::IsNullOrWhiteSpace($$InstallDir) -or -not (Test-Path -LiteralPath $$InstallDir)) { exit 0 }$\r$\n"
FileWrite ${HANDLE} "$$root = [System.IO.Path]::GetFullPath($$InstallDir).TrimEnd('\') + '\'$\r$\n"
FileWrite ${HANDLE} "$$exclude = ''$\r$\n"
FileWrite ${HANDLE} "if (-not [string]::IsNullOrWhiteSpace($$ExcludePath)) { $$exclude = [System.IO.Path]::GetFullPath($$ExcludePath) }$\r$\n"
FileWrite ${HANDLE} "function Get-AntBrowserProcesses {$\r$\n"
FileWrite ${HANDLE} " @(Get-CimInstance Win32_Process | Where-Object {$\r$\n"
FileWrite ${HANDLE} " $$_.ExecutablePath -and $$_.ExecutablePath.StartsWith($$root, [System.StringComparison]::OrdinalIgnoreCase) -and ($$exclude -eq '' -or -not $$_.ExecutablePath.Equals($$exclude, [System.StringComparison]::OrdinalIgnoreCase))$\r$\n"
FileWrite ${HANDLE} " })$\r$\n"
FileWrite ${HANDLE} "}$\r$\n"
FileWrite ${HANDLE} "$$deadline = (Get-Date).AddSeconds(10)$\r$\n"
FileWrite ${HANDLE} "do {$\r$\n"
FileWrite ${HANDLE} " $$procs = Get-AntBrowserProcesses$\r$\n"
FileWrite ${HANDLE} " if (-not $$procs -or $$procs.Count -eq 0) { exit 0 }$\r$\n"
FileWrite ${HANDLE} " foreach ($$p in $$procs) { try { Stop-Process -Id $$p.ProcessId -Force -ErrorAction Stop } catch {} }$\r$\n"
FileWrite ${HANDLE} " Start-Sleep -Milliseconds 400$\r$\n"
FileWrite ${HANDLE} "} while ((Get-Date) -lt $$deadline)$\r$\n"
FileWrite ${HANDLE} "$$left = Get-AntBrowserProcesses$\r$\n"
FileWrite ${HANDLE} "if ($$left -and $$left.Count -gt 0) {$\r$\n"
FileWrite ${HANDLE} " $$names = ($$left | ForEach-Object { $$_.Name + '#' + $$_.ProcessId }) -join ', '$\r$\n"
FileWrite ${HANDLE} " Write-Host ('still running: ' + $$names)$\r$\n"
FileWrite ${HANDLE} " exit 1$\r$\n"
FileWrite ${HANDLE} "}$\r$\n"
FileWrite ${HANDLE} "exit 0$\r$\n"
!macroend
Function CloseInstalledProcesses
IfFileExists "$INSTDIR" 0 done
retry_powershell:
IfFileExists "${POWERSHELL_EXE}" 0 fallback_taskkill
GetTempFileName $0
Delete $0
StrCpy $0 "$0.ps1"
FileOpen $1 $0 w
!insertmacro WriteCloseProcessScript $1
FileClose $1
DetailPrint "正在关闭安装目录中的残留进程: $INSTDIR"
ExecWait '"${POWERSHELL_EXE}" -NoProfile -ExecutionPolicy Bypass -File "$0" -InstallDir "$INSTDIR" -ExcludePath ""' $2
Delete $0
${If} $2 == 0
Goto done
${EndIf}
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "检测到旧版本仍有进程占用安装目录。$\r$\n$\r$\n目录:$INSTDIR$\r$\n$\r$\n点击“重试”将再次尝试关闭残留进程,点击“取消”将终止本次安装。" IDRETRY retry_powershell IDCANCEL install_abort
install_abort:
Abort "安装已取消:安装目录中的旧进程仍未退出。"
fallback_taskkill:
DetailPrint "PowerShell 不可用,回退到 taskkill 清理主进程和代理进程..."
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM ${PRODUCT_EXE}' $2
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM xray.exe' $2
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM sing-box.exe' $2
Sleep 1500
done:
FunctionEnd
Function un.CloseInstalledProcesses
IfFileExists "$INSTDIR" 0 done
retry_powershell:
IfFileExists "${POWERSHELL_EXE}" 0 fallback_taskkill
GetTempFileName $0
Delete $0
StrCpy $0 "$0.ps1"
FileOpen $1 $0 w
!insertmacro WriteCloseProcessScript $1
FileClose $1
DetailPrint "正在关闭安装目录中的残留进程: $INSTDIR"
ExecWait '"${POWERSHELL_EXE}" -NoProfile -ExecutionPolicy Bypass -File "$0" -InstallDir "$INSTDIR" -ExcludePath "$INSTDIR\Uninstall.exe"' $2
Delete $0
${If} $2 == 0
Goto done
${EndIf}
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "检测到安装目录中仍有旧进程占用文件。$\r$\n$\r$\n目录:$INSTDIR$\r$\n$\r$\n点击“重试”将再次尝试关闭残留进程,点击“取消”将终止本次卸载。" IDRETRY retry_powershell IDCANCEL uninstall_abort
uninstall_abort:
Abort "卸载已取消:安装目录中的旧进程仍未退出。"
fallback_taskkill:
DetailPrint "PowerShell 不可用,回退到 taskkill 清理主进程和代理进程..."
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM ${PRODUCT_EXE}' $2
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM xray.exe' $2
ExecWait '"$SYSDIR\taskkill.exe" /F /T /IM sing-box.exe' $2
Sleep 1500
done:
FunctionEnd
Function WarnInstallDir
StrCpy $0 "$INSTDIR"
StrCpy $1 "$0" 2
${If} "$1" == "C:"
Goto warn_dir
${EndIf}
${If} "$1" == "c:"
Goto warn_dir
${EndIf}
StrLen $1 "$PROGRAMFILES64"
${If} $1 > 0
StrCpy $2 "$0" $1
${If} "$2" == "$PROGRAMFILES64"
Goto warn_dir
${EndIf}
${EndIf}
StrLen $1 "$PROGRAMFILES"
${If} $1 > 0
StrCpy $2 "$0" $1
${If} "$2" == "$PROGRAMFILES"
Goto warn_dir
${EndIf}
${EndIf}
StrLen $1 "$PROGRAMFILES32"
${If} $1 > 0
StrCpy $2 "$0" $1
${If} "$2" == "$PROGRAMFILES32"
Goto warn_dir
${EndIf}
${EndIf}
Return
warn_dir:
MessageBox MB_ICONEXCLAMATION|MB_OKCANCEL|MB_DEFBUTTON2 "不建议安装到 C 盘、Program Files 或其他受权限保护的目录。$\r$\n$\r$\nAnt Browser 会在安装目录写入 data、浏览器实例和运行时文件;普通权限运行时可能写入失败,导致再次启动闪退或浏览器实例启动失败。$\r$\n$\r$\n建议改为非 C 盘可写目录,例如 D:\software\Ant Browser 或 E:\software\Ant Browser。$\r$\n$\r$\n点击“确定”继续安装到当前目录,点击“取消”返回修改安装路径。" IDOK continue_install IDCANCEL cancel_install
continue_install:
Return
cancel_install:
Abort
FunctionEnd
Name "${PRODUCT_NAME} ${VERSION}"
OutFile "..\publish\output\AntBrowser-Setup-${VERSION}.exe"
InstallDir "${INSTALL_DIR}"
InstallDirRegKey HKLM "${UNINSTALL_KEY}" "InstallLocation"
RequestExecutionLevel admin
!ifdef BESTCOMPRESSION
SetCompressor /SOLID lzma
!else
SetCompressor lzma
!endif
!define MUI_ICON "..\build\windows\icon.ico"
!define MUI_UNICON "..\build\windows\icon.ico"
!insertmacro MUI_PAGE_WELCOME
!define MUI_DIRECTORYPAGE_TEXT_TOP "请选择 Ant Browser 的安装目录。建议安装到非 C 盘的可写目录,例如 D:\software\Ant Browser 或 E:\software\Ant Browser;不要安装到 C 盘、Program Files 或其他受权限保护的目录。"
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "安装目录(建议非 C 盘)"
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE WarnInstallDir
!insertmacro MUI_PAGE_DIRECTORY
!define MUI_COMPONENTSPAGE_SMALLDESC
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_EXE}"
!define MUI_FINISHPAGE_RUN_TEXT "Launch Ant Browser"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "SimpChinese"
Section "Ant Browser (required)" SecMain
SectionIn RO
Call CloseInstalledProcesses
SetOutPath "$INSTDIR"
File "${STAGINGDIR}\${PRODUCT_EXE}"
File /oname=${PRODUCT_ICON} "..\build\windows\icon.ico"
!if /FileExists "${STAGINGDIR}\config.yaml"
IfFileExists "$INSTDIR\config.yaml" +2 0
File "${STAGINGDIR}\config.yaml"
!else
!echo "Warning: ${STAGINGDIR}\\config.yaml not found, installer will use runtime defaults."
!endif
!if /FileExists "${STAGINGDIR}\chrome\*"
SetOutPath "$INSTDIR\chrome"
File /r "${STAGINGDIR}\chrome\*"
SetOutPath "$INSTDIR"
!endif
CreateDirectory "$INSTDIR\data"
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayVersion" "${VERSION}"
WriteRegStr HKLM "${UNINSTALL_KEY}" "Publisher" "Ant Chrome Team"
WriteRegStr HKLM "${UNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "${UNINSTALL_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_ICON}"
WriteRegStr HKLM "${UNINSTALL_KEY}" "NoModify" "1"
WriteRegStr HKLM "${UNINSTALL_KEY}" "NoRepair" "1"
WriteUninstaller "$INSTDIR\Uninstall.exe"
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_EXE}" "" "$INSTDIR\${PRODUCT_ICON}"
CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\${PRODUCT_ICON}"
SectionEnd
Section "Proxy Runtime (xray / sing-box)" SecRuntime
SectionIn RO
SetOutPath "$INSTDIR\bin"
File "${STAGINGDIR}\bin\xray.exe"
File "${STAGINGDIR}\bin\sing-box.exe"
SectionEnd
Section /o "Desktop Shortcut" SecDesktop
CreateShortcut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_EXE}" "" "$INSTDIR\${PRODUCT_ICON}"
SectionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecMain} "Ant Browser main program and default config (required)"
!insertmacro MUI_DESCRIPTION_TEXT ${SecRuntime} "xray and sing-box proxy tools (vless/vmess/hysteria2)"
!insertmacro MUI_DESCRIPTION_TEXT ${SecDesktop} "Create a shortcut on the desktop"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section "Uninstall"
Call un.CloseInstalledProcesses
Delete /REBOOTOK "$INSTDIR\${PRODUCT_EXE}"
Delete /REBOOTOK "$INSTDIR\${PRODUCT_ICON}"
Delete /REBOOTOK "$INSTDIR\config.yaml"
Delete /REBOOTOK "$INSTDIR\proxies.yaml"
Delete /REBOOTOK "$INSTDIR\Uninstall.exe"
RMDir /r /REBOOTOK "$INSTDIR\bin"
RMDir /r /REBOOTOK "$INSTDIR\chrome"
Delete /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
Delete /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
RMDir /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME}"
Delete /REBOOTOK "$DESKTOP\${PRODUCT_NAME}.lnk"
DeleteRegKey HKLM "${UNINSTALL_KEY}"
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "是否彻底清理所有用户数据?$\r$\n$\r$\n选择“是”将删除 data 目录(含数据库/实例数据)以及安装目录残留文件。$\r$\n此操作不可恢复。" IDYES un_remove_all_data IDNO un_keep_user_data
un_remove_all_data:
RMDir /r /REBOOTOK "$INSTDIR\data"
RMDir /r /REBOOTOK "$INSTDIR\logs"
RMDir /r /REBOOTOK "$INSTDIR"
Goto un_done
un_keep_user_data:
RMDir /REBOOTOK "$INSTDIR"
Goto un_done
un_done:
IfFileExists "$INSTDIR\." 0 +2
MessageBox MB_ICONEXCLAMATION|MB_OK "检测到部分文件仍被占用,已标记为重启后自动删除。"
SectionEnd