From a236ee61b0bf4b5a7e57965c48181c9abc87b980 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Mon, 9 Nov 2026 21:22:48 +0800 Subject: [PATCH] feat(windows): reinstall an existing Service during NSIS upgrades The reinstall page runs the previous uninstaller, which removes the Service, and the new installer only tried to start one. Record whether clash_verge_service exists, with its start type and running state, in .onInit before that uninstaller can run. When it existed, Section Install reinstalls it with the bundled cores and their hashes through the installer's own elevation, then restores a non-automatic start type and the stopped state. A first install still never adds a Service. A failed reinstall or restore is logged, shown in a warning dialog that is auto-confirmed under /S, and sets exit code 2, so the installer does not report success. Validated only by compiling the macros with makensis -WX against the real SimpleSC plugin; not run on Windows. Refs #8553 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Changelog.md | 4 ++ src-tauri/packages/windows/installer.nsi | 70 +++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 307e88622..84ac7c589 100644 --- a/Changelog.md +++ b/Changelog.md @@ -48,6 +48,10 @@ - 优化连接、规则和日志筛选:切换页面后保留过滤条件 - 优化全局模式代理列表:仅显示 `GLOBAL` 节点,选中其中的策略组时才显示该组 +**🖥️ Windows** + +- 优化 Windows 升级安装时自动重装已安装的服务并保留启停设置,重装失败时提示 + **🍎 macOS** - 优化 macOS TUN 模式的系统 DNS,增加阿里和 Cloudflare 地址 diff --git a/src-tauri/packages/windows/installer.nsi b/src-tauri/packages/windows/installer.nsi index 9df40e8c6..dcdcc2992 100644 --- a/src-tauri/packages/windows/installer.nsi +++ b/src-tauri/packages/windows/installer.nsi @@ -77,6 +77,9 @@ Var VC_REDIST_URL Var VC_REDIST_EXE Var VC_RUNTIME_READY Var VC_RUNTIME_NEEDED +Var ServiceExisted +Var ServiceStartType +Var ServiceWasRunning Name "${PRODUCTNAME}" BrandingText "${COPYRIGHT}" @@ -466,6 +469,34 @@ FunctionEnd {{#each language_files}} !include "{{this}}" {{/each}} +!ifdef LANG_ENGLISH + LangString serviceReinstallFailed ${LANG_ENGLISH} "The ${PRODUCTNAME} Service could not be reinstalled (code $0). Open ${PRODUCTNAME} and reinstall the Service to restore Service mode." +!endif +!ifdef LANG_SIMPCHINESE + LangString serviceReinstallFailed ${LANG_SIMPCHINESE} "${PRODUCTNAME} 服务重装失败(代码 $0)。请打开 ${PRODUCTNAME} 重新安装服务以恢复服务模式。" +!endif +!ifdef LANG_RUSSIAN + LangString serviceReinstallFailed ${LANG_RUSSIAN} "Не удалось переустановить службу ${PRODUCTNAME} (код $0). Откройте ${PRODUCTNAME} и переустановите службу, чтобы восстановить режим службы." +!endif + +!macro RecordVergeService + StrCpy $ServiceExisted 0 + StrCpy $ServiceStartType "" + StrCpy $ServiceWasRunning 1 + SimpleSC::ExistsService "clash_verge_service" + Pop $0 + ${If} $0 == 0 + StrCpy $ServiceExisted 1 + SimpleSC::GetServiceStartType "clash_verge_service" + Pop $0 + Pop $1 + ${IfThen} $0 == 0 ${|} StrCpy $ServiceStartType $1 ${|} + SimpleSC::ServiceIsRunning "clash_verge_service" + Pop $0 + Pop $1 + ${IfThen} $0 == 0 ${|} StrCpy $ServiceWasRunning $1 ${|} + ${EndIf} +!macroend Function .onInit ${GetOptions} $CMDLINE "/P" $PassiveMode @@ -483,6 +514,9 @@ Function .onInit StrCpy $UpdateMode 1 ${EndIf} + ; Recorded before the reinstall page can run the previous uninstaller, which removes the Service. + !insertmacro RecordVergeService + !if "${DISPLAYLANGUAGESELECTOR}" == "true" ; Auto-update forwards the app's UI language as `/LANG=` so ; the installer uses it directly and skips the interactive language @@ -663,6 +697,36 @@ FunctionEnd ${EndIf} !macroend +; Reinstalls the Service with the bundled cores, then restores the recorded start type and stopped state. +!macro ReinstallVergeService + StrCpy $R0 '"$INSTDIR\resources\clash-verge-service-install.exe" --install-service' + !ifdef MIHOMO_SHA256 + StrCpy $R0 '$R0 --install-core "$INSTDIR\verge-mihomo.exe" --sha256 "${MIHOMO_SHA256}"' + !endif + !ifdef MIHOMO_ALPHA_SHA256 + StrCpy $R0 '$R0 --install-core "$INSTDIR\verge-mihomo-alpha.exe" --sha256 "${MIHOMO_ALPHA_SHA256}"' + !endif + DetailPrint "Reinstalling ${PRODUCTNAME} Service..." + nsExec::ExecToLog $R0 + Pop $0 + ${If} $0 == 0 + ${AndIf} $ServiceStartType != "" + ${AndIf} $ServiceStartType != 2 + SimpleSC::SetServiceStartType "clash_verge_service" $ServiceStartType + Pop $0 + ${EndIf} + ${If} $0 == 0 + ${AndIf} $ServiceWasRunning == 0 + SimpleSC::StopService "clash_verge_service" 1 30 + Pop $0 + ${EndIf} + ${If} $0 != 0 + DetailPrint "Reinstalling ${PRODUCTNAME} Service failed ($0)" + MessageBox MB_OK|MB_ICONEXCLAMATION "$(serviceReinstallFailed)" /SD IDOK + SetErrorLevel 2 + ${EndIf} +!macroend + !macro RemoveVergeService ; Check if the service exists SimpleSC::ExistsService "clash_verge_service" @@ -985,7 +1049,11 @@ Section Install ${IfThen} $0 != 0 ${|} DetailPrint "Staging verge-mihomo-alpha returned $0" ${|} !endif - !insertmacro StartVergeService + ${If} $ServiceExisted = 1 + !insertmacro ReinstallVergeService + ${Else} + !insertmacro StartVergeService + ${EndIf} ; Create file associations {{#each file_associations as |association| ~}}