!macro customInstall ; Local AI (llama.cpp) requires the Microsoft VC++ 2015-2022 x64 runtime. ; Fresh Windows / TV PCs often do not have it preinstalled. IfFileExists "$INSTDIR\resources\app.asar.unpacked\vendor\redist\vc_redist.x64.exe" 0 +2 ExecWait '"$INSTDIR\resources\app.asar.unpacked\vendor\redist\vc_redist.x64.exe" /install /quiet /norestart' $0 !macroend ; --------------------------------------------------------------------------------------------------- ; Replaces electron-builder's "is the app running?" check (customCheckAppRunning). Runs at the start of ; installing, BEFORE the old version is removed and before any file is copied. ; ; The stock check only looks for "Bible App.exe". But the app also starts programs from its own folder ; - the local AI server (llama-server.exe), speech (whisper), the upscaler - and if the app is closed ; hard, those are left running. They hold their files open, so copying the new version fails and the ; installer says "Bible App cannot be closed. Please close it manually and click Retry" even though ; the app is plainly closed, and Retry can never succeed. So: ; 1. ask the app to close (it then stops the AI server itself), and give it a moment; ; 2. force-close anything named Bible App.exe that is still there; ; 3. force-close the app's own helper programs by name (plain taskkill, nothing to go wrong); ; 4. as a backstop, force-close EVERY program running from this install folder, whatever its name. ; Step 4 matches by folder, via WMI (works from this 32-bit installer on 64-bit Windows, where a ; 32-bit process cannot read a 64-bit process's path). The folder travels in an environment variable ; so a quote or space in it can never break the command, and it refuses to act on a bare drive. ; No question is asked first: installing this version replaces the app, which is what was asked for. ; --------------------------------------------------------------------------------------------------- !macro customCheckAppRunning DetailPrint `Closing "${PRODUCT_NAME}"...` nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "USERNAME eq %USERNAME%"` Pop $0 Sleep 2500 nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /t /im "${APP_EXECUTABLE_FILENAME}" /fi "USERNAME eq %USERNAME%"` Pop $0 nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /t /im llama-server.exe /im whisper-cli.exe /im realesrgan-ncnn-vulkan.exe /fi "USERNAME eq %USERNAME%"` Pop $0 System::Call 'Kernel32::SetEnvironmentVariable(t "BIBLEAPP_INSTDIR", t "$INSTDIR")' StrCpy $1 "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" ${If} ${FileExists} "$WINDIR\Sysnative\WindowsPowerShell\v1.0\powershell.exe" StrCpy $1 "$WINDIR\Sysnative\WindowsPowerShell\v1.0\powershell.exe" ${EndIf} StrCpy $2 `"$1" -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$$r = $$env:BIBLEAPP_INSTDIR.TrimEnd('\'); if ($$r.Split('\').Count -lt 2) { exit }; $$d = $$r + '\'; Get-CimInstance Win32_Process | Where-Object { $$_.ExecutablePath -and $$_.ExecutablePath.StartsWith($$d, [StringComparison]::OrdinalIgnoreCase) } | ForEach-Object { Stop-Process -Id $$_.ProcessId -Force -ErrorAction SilentlyContinue }"` DetailPrint `Closing anything else still running from "${PRODUCT_NAME}"'s folder...` nsExec::Exec $2 Pop $0 Sleep 1000 !insertmacro bibleAppSkipDamagedUninstaller SHELL_CONTEXT !insertmacro bibleAppSkipDamagedUninstaller HKCU !macroend ; --------------------------------------------------------------------------------------------------- ; Versions 1.4.35 - 1.4.37 were built on macOS before build/installerIcon.ico existed, and their ; uninstallers are damaged: they fail NSIS's own integrity check ("Installer integrity check has ; failed"). electron-builder rebuilds the uninstaller in JavaScript on macOS and leaves out NSIS's ; icon patch, so whenever the installer and uninstaller icons differ (NSIS's two defaults do), the ; checksum is wrong. An update runs the PREVIOUS version's uninstaller first, so those versions could ; never be updated: the damaged uninstaller fails, and the installer reports "Bible App cannot be ; closed" (it also cannot be uninstalled from Windows Settings). ; ; For exactly those versions, the old uninstaller is not run: its UninstallString is cleared, so ; electron-builder's uninstallOldVersion finds nothing to run, and the new files are copied over the ; old ones. This installer then writes a fresh, valid uninstaller and registry entry. Every other ; version still goes through the normal uninstall-then-install path. ; --------------------------------------------------------------------------------------------------- !macro bibleAppSkipDamagedUninstaller ROOT ReadRegStr $3 ${ROOT} "${UNINSTALL_REGISTRY_KEY}" DisplayVersion ${If} $3 == "1.4.35" ${OrIf} $3 == "1.4.36" ${OrIf} $3 == "1.4.37" DetailPrint `Version $3's uninstaller is damaged; installing over it instead.` DeleteRegValue ${ROOT} "${UNINSTALL_REGISTRY_KEY}" UninstallString !ifdef UNINSTALL_REGISTRY_KEY_2 DeleteRegValue ${ROOT} "${UNINSTALL_REGISTRY_KEY_2}" UninstallString !endif ${EndIf} !macroend