Files
punktfunk/docs/windows-service.md
T
enricobuehler 16d3b7767e
apple / swift (push) Successful in 54s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
windows-host / package (push) Failing after 6m18s
android / android (push) Failing after 2m12s
ci / web (push) Successful in 38s
ci / rust (push) Failing after 1m40s
ci / docs-site (push) Successful in 29s
deb / build-publish (push) Successful in 2m35s
decky / build-publish (push) Successful in 24s
ci / bench (push) Successful in 4m32s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 3m35s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 20s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m33s
docker / deploy-docs (push) Successful in 22s
feat(packaging): signed Inno Setup installer for the Windows host + CI
MSIX (the client's format) can't install the host's LocalSystem secure-desktop
service or the SudoVDA kernel driver, so the host ships as a signed Inno Setup
setup.exe that runs elevated and delegates to the existing idempotent
`punktfunk-host service install`.

- packaging/windows/punktfunk-host.iss: lay exe into Program Files, optional
  SudoVDA driver task, run service install/start; [Code] stops+waits the service
  before file copy on upgrade; uninstall runs service uninstall.
- pack-host-installer.ps1: cert (reuses MSIX_CERT_PFX_B64 / self-signed CN=unom),
  sign inner exe + setup.exe, fetch/stage SudoVDA, run ISCC, export public .cer.
- fetch-sudovda.ps1 / install-sudovda.ps1: pinned SudoVDA + nefcon download, cert
  import, gated device-node create (no phantom dup), pnputil install (warn-not-abort).
- nvenc/: synthesize nvencodeapi.lib via llvm-dlltool from a 2-export .def so
  --features nvenc links with no GPU/SDK at build time.
- .gitea/workflows/windows-host.yml: build (nvenc) -> clippy -> ISCC -> sign ->
  publish setup.exe + .cer to the generic registry pkg punktfunk-host-windows.
  Tag host-win-v* -> X.Y.Z (+ latest/ alias); main push -> rolling 0.2.<run>.
- setup-windows-runner.ps1: provision Inno Setup; docs: installer instructions.

SudoVDA/nefcon release URLs+SHA-256s in fetch-sudovda.ps1 are placeholders
(baseline v0.2.1) — fetch warns + prints the computed hash until pinned.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 23:05:20 +00:00

4.9 KiB

Windows service (deployment)

The PunktfunkHost Windows service is the end-user way to run the host on Windows. It replaces the manual bring-up chain (a scheduled task → PsExec64 -s -i 1wscript launch.vbshost-run.cmd) with one command, auto-start on boot, and supervision.

Download the signed installer from the package registry (punktfunk-host-windows, https://git.unom.io/unom/-/packages) and run it (it elevates itself):

punktfunk-host-setup-<ver>.exe              # wizard
punktfunk-host-setup-<ver>.exe /VERYSILENT  # unattended

It lays the host into C:\Program Files\punktfunk, optionally installs the bundled SudoVDA virtual-display driver, then runs service install + service start for you. Upgrades stop the service first and re-point it; uninstall (Add/Remove Programs) runs service uninstall. Packaging details: packaging/windows/README.md. A self-signed CI build also publishes a .cer — import it once (Import-Certificate -FilePath punktfunk-host-windows.cer -CertStoreLocation Cert:\LocalMachine\TrustedPublisher) so Windows trusts the signed setup.

Install (manual / CLI)

From an elevated (Administrator) prompt:

punktfunk-host service install   # register auto-start LocalSystem service + firewall rules + default host.env
punktfunk-host service start     # start it now (also starts automatically on every boot)

service install is idempotent — run it again after upgrading the exe to re-point the service at the new binary. Register whatever location you keep the exe in (e.g. C:\Program Files\punktfunk\); the service records the current exe path.

Other subcommands:

punktfunk-host service stop
punktfunk-host service status
punktfunk-host service uninstall   # stop + delete the service + remove its firewall rules

How it works

The host must run as SYSTEM in the interactive session (Session 1+): Desktop Duplication of the secure desktop (UAC / lock / login) and SendInput need SYSTEM, and capture/injection need the interactive session, which a plain Session-0 service is not in.

So the service (itself in Session 0) never captures. On start, and whenever the active console session changes, it:

  1. resolves the active console session (WTSGetActiveConsoleSessionId),
  2. duplicates its own LocalSystem token and retargets it to that session (SetTokenInformation TokenSessionId),
  3. launches the host there with CreateProcessAsUserW (lpDesktop = winsta0\default),
  4. supervises it: relaunches on exit/crash (with backoff) and on a console connect/disconnect.

A kill-on-close job object ensures a service crash never orphans the SYSTEM host. The host in turn spawns the WGC helper into the user session (see windows-secure-desktop.md) — two nested launches. Lock/unlock are handled inside the host (the DesktopWatcher DDA↔WGC mux), so the service deliberately does not relaunch on lock/unlock — only on a real session switch.

This is the same model Sunshine/Apollo use.

Configuration

Config lives in %ProgramData%\punktfunk\host.env (KEY=VALUE lines, # comments). service install writes a default if none exists. Template: scripts/windows/host.env.example.

PUNKTFUNK_ENCODER=nvenc
PUNKTFUNK_VIDEO_SOURCE=virtual
PUNKTFUNK_SECURE_DDA=1
RUST_LOG=info
# PUNKTFUNK_HOST_CMD=serve --native    # the host subcommand the service launches (default)

The service loads these into its environment and carries PUNKTFUNK_* + RUST_LOG to the host child (the same env-merge the WGC helper uses). Restart the service after editing:

punktfunk-host service stop; punktfunk-host service start

The host's identity (cert/pairing/mgmt token/library) also lives under %ProgramData%\punktfunk — a machine-wide dir the SYSTEM service and the interactive user share, surviving user logout. PUNKTFUNK_CONFIG_DIR overrides the location (both platforms; handy for tests).

Logs

  • %ProgramData%\punktfunk\logs\service.log — the service's own supervision log (spawn/exit/session switches).
  • %ProgramData%\punktfunk\logs\host.log — the host child's stdout/stderr.

Prerequisites

  • The host built with --features nvenc for NVENC (the driver ships nvEncodeAPI64.dll; no SDK needed at runtime). Software encode otherwise.
  • The SudoVDA indirect display driver installed (for PUNKTFUNK_VIDEO_SOURCE=virtual).
  • ViGEmBus for virtual gamepads (optional).

Gotchas

  • service install/uninstall need an elevated prompt (the SCM rejects non-admin).
  • service run is the SCM entry point — don't run it by hand (it errors with a hint).
  • A graceful stop currently TerminateProcesses the host, so its RAII teardown (SudoVDA monitor REMOVE) doesn't run; a stale virtual monitor can linger until the next start. A cooperative-stop signal is a follow-up.