11; This file is included for both installer and uninstaller builds.
22; Guard installer-only pages/functions to avoid "function not referenced" warnings
33; when electron-builder compiles the standalone uninstaller.
4+ !define /ifndef WDA_DEFAULT_SETTINGS_PATH " $APPDATA\${APP_FILENAME}\desktop-settings.json"
5+ !define /ifndef WDA_DEFAULT_OUTPUT_DIR " $APPDATA\${APP_FILENAME}\output"
6+ !ifdef APP_PRODUCT_FILENAME
7+ !define /ifndef WDA_PRODUCT_SETTINGS_PATH " $APPDATA\${APP_PRODUCT_FILENAME}\desktop-settings.json"
8+ !define /ifndef WDA_PRODUCT_OUTPUT_DIR " $APPDATA\${APP_PRODUCT_FILENAME}\output"
9+ !else
10+ !define /ifndef WDA_PRODUCT_SETTINGS_PATH " "
11+ !define /ifndef WDA_PRODUCT_OUTPUT_DIR " "
12+ !endif
13+ !ifdef APP_PACKAGE_NAME
14+ !define /ifndef WDA_PACKAGE_SETTINGS_PATH " $APPDATA\${APP_PACKAGE_NAME}\desktop-settings.json"
15+ !define /ifndef WDA_PACKAGE_OUTPUT_DIR " $APPDATA\${APP_PACKAGE_NAME}\output"
16+ !else
17+ !define /ifndef WDA_PACKAGE_SETTINGS_PATH " "
18+ !define /ifndef WDA_PACKAGE_OUTPUT_DIR " "
19+ !endif
420!ifndef BUILD_UNINSTALLER
521!include nsDialogs.nsh
622!include LogicLib.nsh
1329!define /ifndef MUI_DIRECTORYPAGE_TEXT_DESTINATION " 安装位置:"
1430
1531Var WDA_InstallDirPage
32+ Var WDA_OutputDirPage
33+ Var WDA_OutputDirInput
34+ Var WDA_OutputDirBrowseButton
35+ Var WDA_SelectedOutputDir
1636
1737!macro customInit
1838 ; Safety: older versions created an `output` junction inside the install directory that points to the
@@ -22,17 +42,10 @@ Var WDA_InstallDirPage
2242!macroend
2343
2444!macro customInstall
25- ; Provide a safe, non-junction way for users to locate the real per-user output directory.
26- ; The actual data is NOT stored inside $INSTDIR (it is wiped on update/reinstall).
27- ; `open-output.cmd` uses %APPDATA% so it works for the current user.
28- FileOpen $0 " $INSTDIR\output-location.txt" w
29- FileWrite $0 " WeChatDataAnalysis output folder (per user):$\r$\n %APPDATA%\\${APP_PACKAGE_NAME}\\output$\r$\n "
30- FileClose $0
31-
32- FileOpen $1 " $INSTDIR\open-output.cmd" w
33- ; NSIS escaping: use $\" to output a literal quote character into the .cmd file.
34- FileWrite $1 " @echo off$\r$\n explorer $\" %APPDATA%\\${APP_PACKAGE_NAME}\\output$\"$\r$\n "
35- FileClose $1
45+ ${If} $WDA_SelectedOutputDir == " "
46+ Call WDA_InitOutputDirSelection
47+ ${EndIf}
48+ Call WDA_WritePendingOutputDirSetting
3649!macroend
3750
3851Function WDA_RemoveLegacyOutputLink
@@ -47,9 +60,27 @@ FunctionEnd
4760 ; the final install location (includes the app sub-folder).
4861 !ifdef allowToChangeInstallationDirectory
4962 Page custom WDA_InstallDirPageCreate WDA_InstallDirPageLeave
63+ Page custom WDA_OutputDirPageCreate WDA_OutputDirPageLeave
5064 !endif
5165!macroend
5266
67+ Function WDA_InitOutputDirSelection
68+ StrCpy $WDA_SelectedOutputDir " ${WDA_DEFAULT_OUTPUT_DIR}"
69+ nsExec::ExecToStack '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "& { param([string] $$defaultSettingsPath, [string] $$defaultOutputPath, [string] $$legacySettingsPath1, [string] $$legacySettingsPath2) $$candidates = @($$defaultSettingsPath, $$legacySettingsPath1, $$legacySettingsPath2) | Where-Object { -not [string]::IsNullOrWhiteSpace($$_) } | Select-Object -Unique; $$settingsPath = $$defaultSettingsPath; foreach ($$candidate in $$candidates) { if (Test-Path -LiteralPath $$candidate) { $$settingsPath = $$candidate; break } }; $$result = $$defaultOutputPath; if (Test-Path -LiteralPath $$settingsPath) { try { $$json = Get-Content -LiteralPath $$settingsPath -Raw | ConvertFrom-Json; $$value = [string] $$json.pendingOutputDir; if ([string]::IsNullOrWhiteSpace($$value)) { $$value = [string] $$json.outputDir }; if ($$value -eq '''') { $$result = $$defaultOutputPath } elseif (-not [string]::IsNullOrWhiteSpace($$value)) { $$result = $$value } } catch {} }; [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; [Console]::Write($$result) }" "${WDA_DEFAULT_SETTINGS_PATH}" "${WDA_DEFAULT_OUTPUT_DIR}" "${WDA_PRODUCT_SETTINGS_PATH}" "${WDA_PACKAGE_SETTINGS_PATH}"'
70+ Pop $0
71+ Pop $1
72+ ${If} $0 == " 0"
73+ ${AndIf} $1 != " "
74+ StrCpy $WDA_SelectedOutputDir " $1"
75+ ${EndIf}
76+ FunctionEnd
77+
78+ Function WDA_WritePendingOutputDirSetting
79+ nsExec::ExecToStack '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "& { param([string] $$defaultSettingsPath, [string] $$defaultOutputPath, [string] $$selectedOutputPath, [string] $$legacySettingsPath1, [string] $$legacySettingsPath2) $$candidates = @($$defaultSettingsPath, $$legacySettingsPath1, $$legacySettingsPath2) | Where-Object { -not [string]::IsNullOrWhiteSpace($$_) } | Select-Object -Unique; $$sourceSettingsPath = $$defaultSettingsPath; foreach ($$candidate in $$candidates) { if (Test-Path -LiteralPath $$candidate) { $$sourceSettingsPath = $$candidate; break } }; if ([string]::IsNullOrWhiteSpace($$selectedOutputPath)) { $$selectedOutputPath = $$defaultOutputPath }; $$pending = if ([string]::Equals($$selectedOutputPath, $$defaultOutputPath, [System.StringComparison]::OrdinalIgnoreCase)) { '''' } else { $$selectedOutputPath }; $$obj = @{}; if (Test-Path -LiteralPath $$sourceSettingsPath) { try { $$existing = Get-Content -LiteralPath $$sourceSettingsPath -Raw | ConvertFrom-Json; if ($$null -ne $$existing) { $$existing.PSObject.Properties | ForEach-Object { $$obj[$$_.Name] = $$_.Value } } } catch {} }; $$obj[''pendingOutputDir''] = $$pending; $$dir = Split-Path -Parent $$defaultSettingsPath; New-Item -ItemType Directory -Force -Path $$dir | Out-Null; $$json = [PSCustomObject] $$obj | ConvertTo-Json -Depth 10; Set-Content -LiteralPath $$defaultSettingsPath -Value $$json -Encoding UTF8 }" "${WDA_DEFAULT_SETTINGS_PATH}" "${WDA_DEFAULT_OUTPUT_DIR}" "$WDA_SelectedOutputDir" "${WDA_PRODUCT_SETTINGS_PATH}" "${WDA_PACKAGE_SETTINGS_PATH}"'
80+ Pop $0
81+ Pop $1
82+ FunctionEnd
83+
5384Function WDA_EnsureAppSubDir
5485 ; Normalize $INSTDIR to always end with "\${APP_FILENAME}" (avoid cluttering a parent folder).
5586 StrCpy $0 " $INSTDIR"
@@ -105,6 +136,48 @@ FunctionEnd
105136Function WDA_InstallDirPageLeave
106137FunctionEnd
107138
139+ Function WDA_OutputDirBrowse
140+ nsDialogs::SelectFolderDialog " 选择 output 目录" " $WDA_SelectedOutputDir"
141+ Pop $0
142+ ${If} $0 != error
143+ StrCpy $WDA_SelectedOutputDir " $0"
144+ ${NSD_SetText} $WDA_OutputDirInput " $0"
145+ ${EndIf}
146+ FunctionEnd
147+
148+ Function WDA_OutputDirPageCreate
149+ Call WDA_InitOutputDirSelection
150+
151+ nsDialogs::Create 1018
152+ Pop $WDA_OutputDirPage
153+
154+ ${If} $WDA_OutputDirPage == error
155+ Abort
156+ ${EndIf}
157+
158+ ${NSD_CreateLabel} 0u 0u 100 % 24u " 请选择 output 目录(保存解密数据库、导出内容、缓存、日志等)。"
159+ Pop $0
160+
161+ ${NSD_CreateText} 0u 28u 78 % 12u " $WDA_SelectedOutputDir"
162+ Pop $WDA_OutputDirInput
163+
164+ ${NSD_CreateButton} 82 % 27u 18 % 14u " 浏览..."
165+ Pop $WDA_OutputDirBrowseButton
166+ ${NSD_OnClick} $WDA_OutputDirBrowseButton WDA_OutputDirBrowse
167+
168+ ${NSD_CreateLabel} 0u 52u 100 % 28u " 安装器只记录你的选择;真正的数据迁移会在首次启动应用时执行。若目标目录已有内容,应用会阻止切换并提示处理。"
169+ Pop $0
170+
171+ nsDialogs::Show
172+ FunctionEnd
173+
174+ Function WDA_OutputDirPageLeave
175+ ${NSD_GetText} $WDA_OutputDirInput $WDA_SelectedOutputDir
176+ ${If} $WDA_SelectedOutputDir == " "
177+ StrCpy $WDA_SelectedOutputDir " ${WDA_DEFAULT_OUTPUT_DIR}"
178+ ${EndIf}
179+ FunctionEnd
180+
108181!endif
109182
110183!ifdef BUILD_UNINSTALLER
@@ -177,6 +250,12 @@ FunctionEnd
177250 RMDir /r " $APPDATA\${APP_PACKAGE_NAME}"
178251 !endif
179252
253+ IfFileExists " $INSTDIR\output-location.path" 0 WDA_SkipCustomOutputDelete
254+ nsExec::ExecToStack ' "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "& { param([string] $$pathFile, [string] $$defaultPath1, [string] $$defaultPath2, [string] $$defaultPath3) if (Test-Path -LiteralPath $$pathFile) { $$target = (Get-Content -LiteralPath $$pathFile -Raw).Trim(); $$defaults = @($$defaultPath1, $$defaultPath2, $$defaultPath3) | Where-Object { -not [string]::IsNullOrWhiteSpace($$_) }; $$isDefault = $$false; foreach ($$defaultPath in $$defaults) { if ([string]::Equals($$target, $$defaultPath, [System.StringComparison]::OrdinalIgnoreCase)) { $$isDefault = $$true; break } }; if (-not $$isDefault -and -not [string]::IsNullOrWhiteSpace($$target) -and (Test-Path -LiteralPath $$target)) { Remove-Item -LiteralPath $$target -Recurse -Force -ErrorAction SilentlyContinue } } }" "$INSTDIR\output-location.path" "${WDA_DEFAULT_OUTPUT_DIR}" "${WDA_PRODUCT_OUTPUT_DIR}" "${WDA_PACKAGE_OUTPUT_DIR}"'
255+ Pop $0
256+ Pop $1
257+ WDA_SkipCustomOutputDelete:
258+
180259 ${if} $installMode == " all"
181260 SetShellVarContext all
182261 ${endif}
0 commit comments