!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 !macroend