Files
WYF-koubo/scripts/installer.nsh
T
2026-06-19 18:45:55 +08:00

348 lines
8.7 KiB
NSIS

!include "LogicLib.nsh"
!define LEGACY_APP_GUID "3a51f54f-dd33-55a2-a302-8f716620a296"
!define LEGACY_INSTALL_KEY "Software\${LEGACY_APP_GUID}"
!define LEGACY_UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${LEGACY_APP_GUID}"
!define LEGACY_UNINSTALL_KEY_WOW64 "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\${LEGACY_APP_GUID}"
Var OldInstallDir
Var OldBundleDir
Var BundleBackupDir
Var UpgradePreparationDone
Function LegacyGetInQuotes
Exch $R0
Push $R1
Push $R2
Push $R3
StrCpy $R2 -1
IntOp $R2 $R2 + 1
StrCpy $R3 $R0 1 $R2
StrCmp $R3 "" 0 +3
StrCpy $R0 ""
Goto legacy_get_in_quotes_done
StrCmp $R3 '"' 0 -5
IntOp $R2 $R2 + 1
StrCpy $R0 $R0 "" $R2
StrCpy $R2 0
IntOp $R2 $R2 + 1
StrCpy $R3 $R0 1 $R2
StrCmp $R3 "" 0 +3
StrCpy $R0 ""
Goto legacy_get_in_quotes_done
StrCmp $R3 '"' 0 -5
StrCpy $R0 $R0 $R2
legacy_get_in_quotes_done:
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
Function LegacyGetFileParent
Exch $R0
Push $R1
Push $R2
Push $R3
StrCpy $R1 0
StrLen $R2 $R0
legacy_get_parent_loop:
IntOp $R1 $R1 + 1
IntCmp $R1 $R2 legacy_get_parent_done 0 legacy_get_parent_done
StrCpy $R3 $R0 1 -$R1
StrCmp $R3 "\" legacy_get_parent_done
Goto legacy_get_parent_loop
legacy_get_parent_done:
StrCpy $R0 $R0 -$R1
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
Function ResolveLegacyInstallDirFromUninstallString
Exch $0
Push $1
Push $2
StrCpy $1 ""
${If} $0 == ""
Goto resolve_legacy_dir_done
${EndIf}
StrCpy $2 $0 1
${If} $2 == '"'
Push $0
Call LegacyGetInQuotes
Pop $1
${Else}
StrCpy $1 $0
${EndIf}
${If} $1 != ""
Push $1
Call LegacyGetFileParent
Pop $1
${EndIf}
resolve_legacy_dir_done:
Pop $2
Exch $1
FunctionEnd
Function ApplyLegacyInstallDirCandidate
Exch $0
${If} $0 != ""
${AndIf} ${FileExists} "$0\*.*"
StrCpy $OldInstallDir "$0"
StrCpy $OldBundleDir "$OldInstallDir\resources-bundles"
StrCpy $INSTDIR "$OldInstallDir"
${EndIf}
Exch $0
FunctionEnd
Function ResolveLegacyInstallDir
${If} $OldInstallDir != ""
${AndIf} ${FileExists} "$OldInstallDir\*.*"
StrCpy $INSTDIR "$OldInstallDir"
Return
${EndIf}
StrCpy $OldInstallDir ""
StrCpy $OldBundleDir ""
ReadRegStr $0 HKCU "${LEGACY_INSTALL_KEY}" "InstallLocation"
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${If} $OldInstallDir == ""
ReadRegStr $0 HKLM "${LEGACY_INSTALL_KEY}" "InstallLocation"
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKCU "${LEGACY_UNINSTALL_KEY}" "InstallLocation"
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY}" "InstallLocation"
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY_WOW64}" "InstallLocation"
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKCU "${LEGACY_UNINSTALL_KEY}" "UninstallString"
Push $0
Call ResolveLegacyInstallDirFromUninstallString
Pop $0
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY}" "UninstallString"
Push $0
Call ResolveLegacyInstallDirFromUninstallString
Pop $0
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir == ""
ReadRegStr $0 HKLM "${LEGACY_UNINSTALL_KEY_WOW64}" "UninstallString"
Push $0
Call ResolveLegacyInstallDirFromUninstallString
Pop $0
Push $0
Call ApplyLegacyInstallDirCandidate
Pop $0
${EndIf}
${If} $OldInstallDir != ""
DetailPrint "Legacy install dir: $OldInstallDir"
${EndIf}
FunctionEnd
Function ClearLegacyRegistry
DeleteRegKey HKCU "${LEGACY_UNINSTALL_KEY}"
DeleteRegKey HKLM "${LEGACY_UNINSTALL_KEY}"
DeleteRegKey HKLM "${LEGACY_UNINSTALL_KEY_WOW64}"
DeleteRegKey HKCU "${LEGACY_INSTALL_KEY}"
DeleteRegKey HKLM "${LEGACY_INSTALL_KEY}"
FunctionEnd
Function RemoveDirectoryDeep
Exch $0
${If} $0 == ""
Return
${EndIf}
ClearErrors
RMDir /r "$0"
ClearErrors
nsExec::ExecToLog '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "$$target = ''\\?\'' + [System.IO.Path]::GetFullPath(''$0''); try { Remove-Item -LiteralPath $$target -Recurse -Force -ErrorAction Stop } catch {}"'
Pop $1
Exch $0
FunctionEnd
Function KillDirectAppProcesses
nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
Pop $0
FunctionEnd
Function KillProcessesUnderLegacyInstall
Call KillDirectAppProcesses
${If} $OldInstallDir == ""
Return
${EndIf}
DetailPrint "Closing processes under $OldInstallDir"
nsExec::ExecToLog '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "$$root = [System.IO.Path]::GetFullPath(''$OldInstallDir''); Get-Process -ErrorAction SilentlyContinue | Where-Object { try { $$path = $$_.Path; if (-not $$path) { return $$false }; [System.IO.Path]::GetFullPath($$path).StartsWith($$root, [System.StringComparison]::OrdinalIgnoreCase) } catch { $$false } } | ForEach-Object { try { Stop-Process -Id $$_.Id -Force -ErrorAction Stop } catch {} }"'
Pop $0
Sleep 1200
Call KillDirectAppProcesses
Sleep 800
FunctionEnd
Function BackupLegacyResourceBundles
${If} $OldBundleDir == ""
Return
${EndIf}
StrCpy $BundleBackupDir "$OldInstallDir.__resources-bundles-backup"
${If} ${FileExists} "$BundleBackupDir\*.*"
${IfNot} ${FileExists} "$OldBundleDir\*.*"
DetailPrint "Reusing preserved resource bundles from $BundleBackupDir"
Return
${EndIf}
${EndIf}
${IfNot} ${FileExists} "$OldBundleDir\*.*"
Return
${EndIf}
Push "$BundleBackupDir"
Call RemoveDirectoryDeep
DetailPrint "Preserving resource bundles to $BundleBackupDir"
Rename "$OldBundleDir" "$BundleBackupDir"
${If} ${Errors}
ClearErrors
nsExec::ExecToLog 'robocopy "$OldBundleDir" "$BundleBackupDir" /E /R:1 /W:1 /NFL /NDL /NJH /NJS /NP'
Pop $0
${EndIf}
FunctionEnd
Function RestorePreservedResourceBundles
${If} $BundleBackupDir == ""
Return
${EndIf}
${IfNot} ${FileExists} "$BundleBackupDir\*.*"
Return
${EndIf}
DetailPrint "Merging preserved resource bundles"
CreateDirectory "$INSTDIR\resources-bundles"
nsExec::ExecToLog 'robocopy "$BundleBackupDir" "$INSTDIR\resources-bundles" /E /XC /XN /XO /R:1 /W:1 /NFL /NDL /NJH /NJS /NP'
Pop $0
Push "$BundleBackupDir"
Call RemoveDirectoryDeep
FunctionEnd
Function RunUpgradePreparation
${If} $UpgradePreparationDone == "true"
Return
${EndIf}
Call ResolveLegacyInstallDir
${If} $OldInstallDir == ""
StrCpy $UpgradePreparationDone "true"
Return
${EndIf}
Call KillProcessesUnderLegacyInstall
Call BackupLegacyResourceBundles
Call ClearLegacyRegistry
StrCpy $UpgradePreparationDone "true"
FunctionEnd
!macro customCheckAppRunning
!ifdef BUILD_UNINSTALLER
DetailPrint "Closing running application..."
nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
Pop $0
!else
DetailPrint "Preparing in-place upgrade..."
Call RunUpgradePreparation
DetailPrint "Upgrade preparation complete"
!endif
!macroend
!macro customInit
Call ResolveLegacyInstallDir
IfSilent skip_vcredist 0
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
StrCmp $0 "1" skip_vcredist
MessageBox MB_YESNO "检测到系统缺少 Visual C++ 运行库,是否安装?" IDYES install_vcredist IDNO skip_vcredist
install_vcredist:
SetOutPath "$TEMP"
File "${BUILD_RESOURCES_DIR}\vc_redist.x64.exe"
ExecWait '"$TEMP\vc_redist.x64.exe" /install /quiet /norestart' $1
Delete "$TEMP\vc_redist.x64.exe"
skip_vcredist:
Call RunUpgradePreparation
!macroend
!macro customInstall
DetailPrint "Running final upgrade checks..."
Call KillProcessesUnderLegacyInstall
Call RestorePreservedResourceBundles
!macroend
!macro customUnInit
DetailPrint "Closing running application..."
nsExec::ExecToLog 'taskkill /F /IM "${PRODUCT_FILENAME}.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "SC-IP-Agent.exe" /T'
Pop $0
nsExec::ExecToLog 'taskkill /F /IM "尚创IP智能体V8.exe" /T'
Pop $0
!macroend