From d7d38af6314223f9452db04bbf321ea378a15155 Mon Sep 17 00:00:00 2001 From: ssbg04 Date: Sun, 11 Oct 2026 11:08:21 +0800 Subject: [PATCH] fix(windows): bundle vc_redist in client installer and download in release workflow --- .github/workflows/release.yml | 27 ++++++++++++++ .gitignore | 1 + frontend/.gitignore | 3 ++ frontend/AGENTS.md | 4 +- frontend/INSTALL.md | 9 +++-- frontend/TIS_RMS_Client.iss | 69 ++++++++++++++++++++++++++++++++--- 6 files changed, 103 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec054fc..578afba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -341,6 +341,33 @@ jobs: $releaseDir = "build\windows\x64\runner\Release" Get-ChildItem -Path "$releaseDir\*.dll" | Select-Object Name, Length + # ------------------------------------------------------------ + # Visual C++ Redistributable Dependency + # ------------------------------------------------------------ + - name: Download Microsoft Visual C++ Redistributable + working-directory: frontend + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + + $vcRedistUrl = "https://aka.ms/vs/17/release/vc_redist.x64.exe" + $vcRedistFile = "vc_redist.x64.exe" + + Write-Host "Downloading Microsoft Visual C++ 2015-2022 Redistributable (x64) from $vcRedistUrl..." + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri $vcRedistUrl -OutFile $vcRedistFile + + if (-not (Test-Path $vcRedistFile)) { + throw "Downloaded vc_redist.x64.exe was not found." + } + + $fileSize = (Get-Item $vcRedistFile).Length + Write-Host "vc_redist.x64.exe downloaded successfully. Size: $fileSize bytes." + + if ($fileSize -lt 10000000) { + throw "Downloaded vc_redist.x64.exe appears incomplete or corrupted (size: $fileSize bytes)." + } + # ------------------------------------------------------------ # Windows Installer # ------------------------------------------------------------ diff --git a/.gitignore b/.gitignore index 544e3ec..afef02b 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ frontend/build/ frontend/android/build/ frontend/.flutter-plugins frontend/.flutter-plugins-dependencies +frontend/vc_redist.x64.exe # Backup logs backend/data/backup_info.json backend/data/backup_logs.txt diff --git a/frontend/.gitignore b/frontend/.gitignore index 776c66c..c2fca81 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -50,3 +50,6 @@ app.*.map.json /android/key.properties .kotlin/ /android/.kotlin/ + +# Visual C++ Redistributable binary (downloaded dynamically during CI / local build) +vc_redist.x64.exe diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md index 90c5aae..29fabbf 100644 --- a/frontend/AGENTS.md +++ b/frontend/AGENTS.md @@ -1054,7 +1054,7 @@ Files backup/restore - mirror mode or zip --> - [x] in-app documentation viewing (bundled offline HTML user guide, local loopback server, embedded WebView for Windows & Android without redirecting to browser) --> -# UI/UX RECOMMENDATIONS ROADMAP (TIS RMS UI-UX Recommendations.md) + - [x] Add lightweight persistent server connection status pill (Connected / Offline). ## Priority 10: Adaptive Tablet / Desktop Navigation -- [x] Implement adaptive Navigation Rail for tablet viewports and maintain persistent sidebar on desktop. +- [x] Implement adaptive Navigation Rail for tablet viewports and maintain persistent sidebar on desktop. --> --- diff --git a/frontend/INSTALL.md b/frontend/INSTALL.md index 8d3a8f9..d1f8581 100644 --- a/frontend/INSTALL.md +++ b/frontend/INSTALL.md @@ -76,8 +76,8 @@ flutter build windows --release --obfuscate --split-debug-info=build/windows/sym The installer script [`frontend/TIS_RMS_Client.iss`](file:///f:/SumbrerongBato/tis_rms_server/frontend/TIS_RMS_Client.iss) packages the app into an ultra-compact standalone setup file (`TIS_RMS_Client_Setup_v.exe` ~**16.7 MB**). #### Features: -- **Small File Size (~17 MB)**: Uses `lzma2/ultra64` solid 64MB dictionary compression. -- **Automated System-Wide VC++ & .NET Runtime Setup**: Automatically detects whether a compatible Visual Studio 2022 (v14.30+) x64 runtime is installed in Windows (`System32`) and silently installs Microsoft's official `vc_redist.x64.exe` if missing or outdated. Also purges legacy app-local CRT DLLs to prevent ABI mismatch crashes. +- **Small File Size**: Uses `lzma2/ultra64` solid compression. +- **Bundled Offline VC++ Runtime Setup**: Packages Microsoft's official `vc_redist.x64.exe` inside the installer. During installation, it detects whether a compatible Visual Studio 2022 (v14.30+) x64 runtime is installed in Windows (`System32`) and silently runs the bundled installer if missing or outdated, reporting errors if installation fails. Also purges legacy app-local CRT DLLs to prevent ABI mismatch crashes. - **Selectable Destination Path**: Lets the user choose where to install (defaults to `C:\Program Files\TIS RMS Client`). - **Desktop Shortcut Checkbox**: Optional checkbox on the tasks page to create a desktop shortcut with the official school icon logo. - **Start Menu & Uninstaller**: Registers a Start Menu program group and includes a clean uninstaller in Windows *Apps & Features* / *Settings*. @@ -85,7 +85,10 @@ The installer script [`frontend/TIS_RMS_Client.iss`](file:///f:/SumbrerongBato/t #### Compiling with Inno Setup CLI: ```powershell -# Using Inno Setup Command Line Compiler (ISCC) +# 1. Download official vc_redist.x64.exe into frontend/ (if not already downloaded) +Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vc_redist.x64.exe" -OutFile "frontend\vc_redist.x64.exe" + +# 2. Compile using Inno Setup Command Line Compiler (ISCC) & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" frontend\TIS_RMS_Client.iss ``` *The compiled installer will be saved to `installers/TIS_RMS_Client_Setup_v.exe` (e.g., `installers/TIS_RMS_Client_Setup_v1.0.0.exe`).* diff --git a/frontend/TIS_RMS_Client.iss b/frontend/TIS_RMS_Client.iss index 5906e4d..4c99b08 100644 --- a/frontend/TIS_RMS_Client.iss +++ b/frontend/TIS_RMS_Client.iss @@ -63,6 +63,8 @@ Source: "build\windows\x64\runner\Release\*.exe"; DestDir: "{app}"; Flags: ignor Source: "build\windows\x64\runner\Release\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Excludes: "msvcp140*.dll,vcruntime140*.dll,concrt140.dll,vccorlib140.dll" Source: "build\windows\x64\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "{#MyAppIcon}"; DestDir: "{app}"; DestName: "app_icon.ico"; Flags: ignoreversion +; Bundled official Microsoft Visual C++ 2015-2022 Redistributable (x64) +Source: "vc_redist.x64.exe"; DestDir: "{tmp}"; Flags: dontcopy [InstallDelete] ; Clean up any legacy app-local MSVC CRT DLLs from older installations so app always uses C:\Windows\System32 @@ -118,17 +120,74 @@ begin RegKeyExists(HKLM, 'SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.WindowsDesktop.App'); end; +// Installs bundled Microsoft Visual C++ Redistributable silently and verifies installation +procedure InstallVCRedist; +var + ResultCode: Integer; + VCRedistPath: String; + PrevStatus: String; +begin + if not IsVCRedistCompatible then + begin + PrevStatus := WizardForm.StatusLabel.Caption; + WizardForm.StatusLabel.Caption := 'Installing Microsoft Visual C++ 2015-2022 Redistributable...'; + try + try + ExtractTemporaryFile('vc_redist.x64.exe'); + VCRedistPath := ExpandConstant('{tmp}\vc_redist.x64.exe'); + + // Run bundled installer silently (/install /quiet /norestart) + if not Exec(VCRedistPath, '/install /quiet /norestart', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then + begin + SuppressibleMsgBox( + 'Failed to execute bundled Microsoft Visual C++ Redistributable installer.' + #13#10 + + 'System Error Code: ' + IntToStr(ResultCode) + #13#10#13#10 + + 'The application requires this runtime component to function properly. Please install vc_redist.x64.exe manually.', + mbError, MB_OK, MB_OK + ); + end + else + begin + // Exit codes: 0 = SUCCESS, 3010 = SUCCESS_REBOOT_REQUIRED, 1641 = SUCCESS_REBOOT_INITIATED, 1638 = ANOTHER_VERSION_ALREADY_INSTALLED + if (ResultCode <> 0) and (ResultCode <> 3010) and (ResultCode <> 1641) and (ResultCode <> 1638) then + begin + SuppressibleMsgBox( + 'Microsoft Visual C++ 2015-2022 Redistributable installation failed.' + #13#10 + + 'Installer Exit Code: ' + IntToStr(ResultCode) + #13#10#13#10 + + 'The application requires this runtime component to function properly. Please install vc_redist.x64.exe manually.', + mbError, MB_OK, MB_OK + ); + end + else if (not IsVCRedistCompatible) and (ResultCode <> 3010) then + begin + SuppressibleMsgBox( + 'Microsoft Visual C++ 2015-2022 Redistributable completed, but runtime verification in the system registry failed.' + #13#10#13#10 + + 'The application requires this runtime component to function properly. Please install vc_redist.x64.exe manually.', + mbError, MB_OK, MB_OK + ); + end; + end; + except + SuppressibleMsgBox( + 'An error occurred while preparing the Visual C++ Redistributable: ' + GetExceptionMessage + #13#10#13#10 + + 'Please install Microsoft Visual C++ 2015-2022 Redistributable (x64) manually.', + mbError, MB_OK, MB_OK + ); + end; + finally + WizardForm.StatusLabel.Caption := PrevStatus; + end; + end; +end; + procedure CurStepChanged(CurStep: TSetupStep); var ResultCode: Integer; begin if CurStep = ssPostInstall then begin - // If Microsoft Visual C++ 2015-2022 Redistributable (x64) is not installed or outdated (< VS 2022), automatically install it silently - if not IsVCRedistCompatible then - begin - Exec('powershell.exe', '-NoProfile -ExecutionPolicy Bypass -Command "$ProgressPreference = ''SilentlyContinue''; try { if (Get-Command winget -ErrorAction SilentlyContinue) { winget install --id Microsoft.VCRedist.2015+.x64 --silent --accept-package-agreements --accept-source-agreements } else { $url = ''https://aka.ms/vs/17/release/vc_redist.x64.exe''; $out = ''$env:TEMP\vc_redist.x64.exe''; Invoke-WebRequest -Uri $url -OutFile $out; Start-Process -FilePath $out -ArgumentList ''/install /quiet /norestart'' -Wait } } catch {}"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); - end; + // Check and install Microsoft Visual C++ 2015-2022 Redistributable + InstallVCRedist; // If .NET Desktop Runtime is not installed, automatically install it silently if not IsDotNetRuntimeInstalled then