Skip to content

Windows build hardening — single-source VERSION, MajorUpgrade, clean uninstall, signing-ready#29

Open
StephenLovino wants to merge 3 commits into
mainfrom
chore/windows-build-hardening
Open

Windows build hardening — single-source VERSION, MajorUpgrade, clean uninstall, signing-ready#29
StephenLovino wants to merge 3 commits into
mainfrom
chore/windows-build-hardening

Conversation

@StephenLovino

Copy link
Copy Markdown
Owner

Summary

Replaces the hardcoded-1.0.0-in-4-places Windows build with an enterprise pipeline. Bump Sources/BetterCastReceiverDesktop/VERSION and CMake, the EXE resource, the NSIS installer, and CI all follow.

What this fixes (from prior support pain)

  • Wrong driver bitness — CI was downloading VirtualDisplayDriver-x86.Driver.Only.zip. Now discovers the x64 asset dynamically via GitHub API and survives upstream renames.
  • Uninstaller leaves driver behind — was looking for VirtualDisplayDriver.inf (wrong name). Now captures the published oem*.inf name into HKLM\Software\BetterCast\VDDOemInf post-install and reads it back at uninstall.
  • Add/Remove Programs always showed 1.0.0makensis was passed a literal 1.0.0. Now driven by VERSION file.
  • Silent ship of broken installerFile /nonfatal + try/catch swallowed VDD download failures. Now hard-fails if MttVDD.inf is missing.
  • VDD was user-deselectable — section is now hidden + SectionIn RO. Components page removed entirely.

Plus, table-stakes enterprise hygiene

  • VS_VERSION_INFO resource → File Properties → Details now populates correctly
  • MajorUpgrade pattern (silently uninstalls old version before installing new)
  • taskkill step so upgrades don't fail on locked files
  • 64-bit guard via ${RunningX64} + SetRegView 64
  • QuietUninstallString, HelpLink, InstallLocation, EstimatedSize reg keys (MDM tools + Windows Update Cleanup recognize the install)
  • Pinned windows-2022 (was floating windows-latest)
  • Concurrency group cancels superseded builds
  • Versioned artifact names (BetterCast-Setup-Windows-x64-1.0.0)
  • Optional code-signing gated on secrets.WINDOWS_CERT_PFX_BASE64 + WINDOWS_CERT_PASSWORD. Signs both EXE and installer with DigiCert timestamping. Skipped silently if secrets absent. Ready for SignPath Foundation.

Test plan

  • CI green on this branch
  • Download installer artifact via nightly.link, install on a clean Windows 10/11 box
  • Verify VDD installs without prompts, virtual display appears in Display Settings
  • Verify EXE File Properties → Details shows correct version, ProductName, Company
  • Verify Add/Remove Programs entry shows correct version + publisher + uninstall link
  • Run uninstaller, confirm pnputil /enum-drivers | findstr -i mttvdd returns nothing
  • Install old release (e.g. existing 1.0.0 from prior CI), then install this build — confirm MajorUpgrade silently replaces it without leaving stale files
  • (When SignPath cert lands) configure the two repo secrets and re-run; confirm both EXE and installer pass signtool verify /pa

Notes

  • Bumps no version number. VERSION is 1.0.0 matching what's been shipping. Bump in a follow-up commit when you're ready to release.
  • The PowerShell helper that captures the published oem*.inf name greps for English field labels (Original Name:, Published Name:). On non-English Windows, capture returns empty and uninstall logs a graceful warning rather than failing — flagging in case you ever ship to a localized OEM image.

🤖 Generated with Claude Code

StephenLovino and others added 3 commits May 1, 2026 07:07
…pgrade, clean uninstall, signing-ready

Replaces the noob-tier 1.0.0-hardcoded-in-4-places Windows build with an
enterprise pipeline. Bump VERSION and everything downstream follows.

Build infrastructure
- Add Sources/BetterCastReceiverDesktop/VERSION as the single source of truth
- CMake reads VERSION, generates Version.h (consumed by main.cpp) and app.rc
  (VS_VERSION_INFO block — EXE File Properties now populate)
- CI reads VERSION and passes both display + numeric versions to NSIS
- Versioned artifact names (BetterCast-Setup-Windows-x64-<version>)

Installer (full rewrite)
- Major-upgrade pattern: detect previous install via uninstall reg key, run
  silent uninstall before laying down new files
- VDD section is hidden + SectionIn RO (was user-deselectable, frequent
  support failure mode); components page removed
- Driver install via pnputil only, hard-fails if MttVDD.inf missing
- Capture published oem*.inf name post-install (PowerShell helper) into
  HKLM\Software\BetterCast\VDDOemInf; uninstaller reads it back and runs
  pnputil /delete-driver /force. Fixes prior bug where uninstall looked for
  VirtualDisplayDriver.inf and silently skipped removal.
- 64-bit guard, SetRegView 64, taskkill on running instance, App Paths reg,
  QuietUninstallString, HelpLink, InstallLocation, EstimatedSize

CI hardening
- Pin to windows-2022 (was windows-latest)
- Concurrency group cancels superseded builds
- Dynamic VDD asset discovery via GitHub API (survives upstream renames,
  fixes prior x86-vs-x64 mismatch)
- Hard-fail if MttVDD.inf missing post-extract — refuse to ship broken
  installer (was silent /nonfatal)
- Verify EXE version metadata after build
- Optional code-signing step gated on WINDOWS_CERT_PFX_BASE64 +
  WINDOWS_CERT_PASSWORD secrets; skipped silently if absent. Signs both
  EXE and installer with DigiCert timestamping. Ready for SignPath.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
VDD release 25.7.23 ships the Intel driver as
VirtualDisplayDriver-x86.Driver.Only.zip — the "-x86" suffix is a
historical misnomer; the package contains the IddCx driver that runs on
x64 Windows. The only true bitness split upstream is ARM64 vs Intel.

Previous CI (now reverted) tried to match an x64-named asset that does
not exist. Restore the working behaviour but make it explicit and
document the misnomer so the next person doesn't repeat my mistake.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The nicehash/NSIS mirror download failed and the winget fallback isn't
available on windows-2022, breaking the Build installer step. The runner
image already ships NSIS at C:\Program Files (x86)\NSIS\ on PATH, so we
just verify makensis is reachable rather than reinstalling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant