Windows client: per-user installer + portable zip as the default download — a stable exe path Steam can launch (overlay, Big Picture); MSIX stays for the Store #349

Merged
enricobuehler merged 1 commits from worktree-win-client-installer into main 2026-08-19 23:05:35 +00:00
Owner

A user reported the Windows client can't be launched via Big Picture and the Steam overlay never appears. The cause isn't UWP — the client is full-trust Win32 under MSIX too — it's the MSIX install shape: the exe lands under the ACL'd WindowsApps dir Steam's Add a Non-Steam Game picker can't browse, and alias/shell:AppsFolder activation defeats the overlay's GameOverlayRenderer64.dll injection (Steam must spawn the exe itself from a normal path). Same reason the overlay doesn't work for Store/Game Pass titles.

So the default download becomes a classic per-user Inno Setup exe (no UAC, %LOCALAPPDATA%\Programs\Punktfunk), with a portable zip beside it. The MSIX keeps being built and published for Microsoft Store compatibility. All three artifacts are packed from the one layout pack-msix.ps1 already assembles.

What's in here

  • punktfunk-client.iss — re-creates the manifest's declarative grants per-user in HKCU: punktfunk:// scheme, flat Start entries (Punktfunk + Punktfunk Console), {app} on the user PATH for the punktfunk CLI (what the Playnite importer shells to). Fetches the Windows App Runtime when missing (ssPostInstall, so silent installs get it too; failure is non-fatal and points at the docs). PATH append/removal are the host installer's helpers retargeted to HKCU.
  • pack-client-installer.ps1 — consumes pack-msix.ps1's layout, signs the four exes individually (the MSIX only signs its container), emits punktfunk-client-setup-<ver>_<arch>.exe + punktfunk-client-windows_<ver>_<arch>-portable.zip. Same signing precedence + fail-closed-on-v*-tags rule as the sibling scripts. No .cer: unlike an MSIX, an exe runs regardless of signer trust.
  • windows-client.yml — pack step after the MSIX (both arches), publish to the generic registry under canary//latest aliases (punktfunk-client-setup_<arch>.exe, punktfunk-client-windows_<arch>-portable.zip), attach to the Gitea release on tags.
  • deeplink.rswrite_shortcut targeted the app-execution alias unconditionally, which doesn't exist without package identity; it now targets the alias when packaged (survives per-update path changes) and current_exe() when not (stable path, no alias). The package-identity probe is now deeplink::has_package_identity(), shared with main.rs's AppUserModelID logic instead of being inlined twice.

User-facing fact changed? Yes — install/update/uninstall steps and the artifact set. Updated in this PR: install-client.md (installer as the default, a Launching through Steam section, portable/MSIX as alternates, MSIX→installer migration note — packaged AppData goes with the package, so one re-pair), channels.md, uninstall.md, clients.md, and data/platforms.json + the byte-copy snapshot (check-docs-drift.sh passes).

Verification — docs drift gate green, cargo fmt --check green, workflow YAML parses. The Rust change compiles only on the Windows runner (this box can't cross-build the MSVC deps) — the PR's build/clippy/test legs are the gate for that, and the packaging steps first exercise for real on the merge-to-main canary run.

Follow-ups, deliberately not here: unom.Punktfunk on the winget source (needs client manifest templates + the source republish job), and an in-app "Add to Steam" button.

A user reported the Windows client can't be launched via Big Picture and the Steam overlay never appears. The cause isn't UWP — the client is full-trust Win32 under MSIX too — it's the MSIX **install shape**: the exe lands under the ACL'd `WindowsApps` dir Steam's *Add a Non-Steam Game* picker can't browse, and alias/`shell:AppsFolder` activation defeats the overlay's `GameOverlayRenderer64.dll` injection (Steam must spawn the exe itself from a normal path). Same reason the overlay doesn't work for Store/Game Pass titles. So the default download becomes a classic per-user Inno Setup exe (no UAC, `%LOCALAPPDATA%\Programs\Punktfunk`), with a portable zip beside it. The MSIX keeps being built and published for Microsoft Store compatibility. All three artifacts are packed from the **one** layout `pack-msix.ps1` already assembles. **What's in here** - `punktfunk-client.iss` — re-creates the manifest's declarative grants per-user in HKCU: `punktfunk://` scheme, flat Start entries (Punktfunk + Punktfunk Console), `{app}` on the user PATH for the `punktfunk` CLI (what the Playnite importer shells to). Fetches the Windows App Runtime when missing (`ssPostInstall`, so silent installs get it too; failure is non-fatal and points at the docs). PATH append/removal are the host installer's helpers retargeted to HKCU. - `pack-client-installer.ps1` — consumes `pack-msix.ps1`'s layout, signs the four exes individually (the MSIX only signs its container), emits `punktfunk-client-setup-<ver>_<arch>.exe` + `punktfunk-client-windows_<ver>_<arch>-portable.zip`. Same signing precedence + fail-closed-on-`v*`-tags rule as the sibling scripts. No `.cer`: unlike an MSIX, an exe runs regardless of signer trust. - `windows-client.yml` — pack step after the MSIX (both arches), publish to the generic registry under `canary/`/`latest` aliases (`punktfunk-client-setup_<arch>.exe`, `punktfunk-client-windows_<arch>-portable.zip`), attach to the Gitea release on tags. - `deeplink.rs` — `write_shortcut` targeted the app-execution alias unconditionally, which doesn't exist without package identity; it now targets the alias when packaged (survives per-update path changes) and `current_exe()` when not (stable path, no alias). The package-identity probe is now `deeplink::has_package_identity()`, shared with `main.rs`'s AppUserModelID logic instead of being inlined twice. **User-facing fact changed?** Yes — install/update/uninstall steps and the artifact set. Updated in this PR: `install-client.md` (installer as the default, a *Launching through Steam* section, portable/MSIX as alternates, MSIX→installer migration note — packaged AppData goes with the package, so one re-pair), `channels.md`, `uninstall.md`, `clients.md`, and `data/platforms.json` + the byte-copy snapshot (`check-docs-drift.sh` passes). **Verification** — docs drift gate green, `cargo fmt --check` green, workflow YAML parses. The Rust change compiles only on the Windows runner (this box can't cross-build the MSVC deps) — the PR's build/clippy/test legs are the gate for that, and the packaging steps first exercise for real on the merge-to-main canary run. Follow-ups, deliberately not here: `unom.Punktfunk` on the winget source (needs client manifest templates + the source republish job), and an in-app "Add to Steam" button.
enricobuehler added 1 commit 2026-08-19 22:53:50 +00:00
Windows client: ship a per-user Inno Setup installer + portable zip as the default download; keep the MSIX for the Store
ci / web (pull_request) Successful in 1m21s
ci / docs-site (pull_request) Successful in 1m32s
ci / bun-nix (pull_request) Successful in 21s
ci / rust-arm64 (pull_request) Successful in 2m4s
ci / docs-drift (pull_request) Successful in 25s
installer-smoke / smoke (arch) (pull_request) Successful in 43s
installer-smoke / smoke (fedora-44) (pull_request) Successful in 1m0s
installer-smoke / smoke (debian-13) (pull_request) Successful in 1m33s
ci / rust (pull_request) Successful in 8m26s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 3m23s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 6m48s
b03acc9153
A user report: launching via Big Picture doesn't work and the Steam overlay never appears.
Not because the app is UWP (it's full-trust Win32 under MSIX too) but because of the MSIX
install SHAPE: the exe lives under the ACL'd WindowsApps dir Steam's non-Steam-game picker
can't browse, and alias/shell:AppsFolder activation defeats the overlay's injection — Steam
must spawn the exe itself from a normal path.

- punktfunk-client.iss: per-user (no UAC) install to %LOCALAPPDATA%\Programs\Punktfunk.
  Re-creates the manifest's grants in HKCU (punktfunk:// scheme, Start entries, {app} on the
  user PATH for the punktfunk CLI) and fetches the Windows App Runtime when missing.
- pack-client-installer.ps1: consumes pack-msix.ps1's layout (one assembly, three artifacts),
  signs the four exes individually, emits setup.exe + a portable zip. Same signing backends
  and fail-closed-on-tags rule as the sibling scripts; no .cer (an exe runs untrusted).
- windows-client.yml: pack step after the MSIX, publish + release-attach the new artifacts
  (canary/latest aliases punktfunk-client-setup_<arch>.exe, ..._<arch>-portable.zip).
- deeplink.rs: write_shortcut targets the app-execution alias only under package identity;
  unpackaged installs have no alias but a stable path, so they target current_exe().
  has_package_identity() now shared with main.rs's AppUserModelID probe.
- docs: install-client (installer default + a 'Launching through Steam' section + MSIX/portable
  as alternates), channels, uninstall, clients, platforms.json (both copies, drift check green).
enricobuehler scheduled this pull request to auto merge when all checks succeed 2026-08-19 23:05:31 +00:00
enricobuehler merged commit d801cb72f2 into main 2026-08-19 23:05:35 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#349