The pf-vdisplay virtual-display driver shipped as a checked-in PREBUILT binary
that went stale - two field failures on a fresh install (live-repro'd on a
German-locale Dell laptop):
* Bug A (every box): a repo-wide rename edited the vendored pf_vdisplay.inf
but never re-signed pf_vdisplay.cat, so the catalog stopped covering the INF
-> `pnputil /add-driver` fails SPAPI_E_FILE_HASH_NOT_IN_CATALOG -> driver
never installs -> every session dies "pf-vdisplay driver interface not
found".
* the prebuilt binary also predated IOCTL_SET_RENDER_ADAPTER (added to the
driver source after the vendor freeze) that the host needs to pin the IDD
render GPU on hybrid/Optimus boxes.
Fix: build the driver FROM SOURCE every release (build-pf-vdisplay.ps1, wired
into pack-host-installer.ps1) so .dll/.inf/.cat are always in lockstep and
current driver features ship. The runner's clang 22 made the driver's pinned
bindgen 0.71 emit opaque structs (157 layout-assert errors), so bump the
vendored wdk-sys/wdk-build bindgen 0.71 -> 0.72 (+ lock). The build self-signs
the driver per build (installer trusts the bundled .cer); a stable
DRIVER_CERT_PFX_B64 secret can override.
* Bug B (non-English boxes): the installer runs install-pf-vdisplay.ps1 etc.
via powershell.exe (5.1), which reads a BOM-less script in the ANSI codepage
- an em-dash's trailing 0x94 byte becomes a curly quote on German
Windows-1252 and the script aborts "unterminated string", so the driver
never installed (the gamepad script survived only because it was already
ASCII). Scrub every installer-run .ps1/.cmd to ASCII + add a CI gate that
fails on any non-ASCII so it can't regress.
* Bug C (upgrades): nothing stopped the OLD web console before re-registering
its task, so a stale server kept :3000 (the new one restart-looped on
EADDRINUSE) and served a broken old bundle (500 on /login). Stop + reap it
(runtime-agnostic, by the :3000 listener owner) in web-setup.ps1 and in the
.iss before the file copy + on uninstall.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Windows host build/deploy scripts
Helper scripts for the Windows host box (the RTX .173 lab box, repo at
C:\Users\Public\punktfunk-native). Run them from the repo root in an elevated PowerShell.
One-time: persist the build environment
powershell -ExecutionPolicy Bypass -File scripts\windows\setup-build-env.ps1
Persists (Machine scope) the three vars the NVENC build needs:
| var | value | why |
|---|---|---|
PUNKTFUNK_NVENC_LIB_DIR |
C:\Users\Public\nvenc |
NVENC import lib (nvencodeapi.lib) |
LIBCLANG_PATH |
C:\Program Files\LLVM\bin |
bindgen (libclang.dll) |
CMAKE_POLICY_VERSION_MINIMUM |
3.5 |
audiopus_sys / cmake crates |
FFMPEG_DIR is not set — the --features nvenc build the RTX box uses does not link
libavcodec (that is only the amf-qsv feature). The VS C++ toolchain is loaded per-build via
vcvars64.bat (auto-discovered with vswhere).
Rebuild + redeploy the host service
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-host.ps1
Stops PunktfunkHost, backs up the current binary (punktfunk-host.exe.bak), builds
--release -p punktfunk-host --features nvenc from the current source, then restarts the
service on the new binary — with automatic rollback if the build fails or the new binary
won't start. The service is down only for the build duration.
Web management console
On an installed host (the setup.exe) the console is set up automatically — no manual steps.
The installer bundles the built (self-contained, no-node_modules) .output server + a portable
bun and runs scripts\windows\web-setup.ps1, which registers the PunktfunkWeb scheduled task
(at boot, as SYSTEM, restart-on-failure) running {app}\web\web-run.cmd →
bun …\.output\server\index.mjs on :3000, opens inbound TCP 3000, and writes the login password to
%ProgramData%\punktfunk\web-password (ACL'd to Administrators + SYSTEM). The mgmt bearer token it
proxies with is the host's own %ProgramData%\punktfunk\mgmt-token. Browse http://<host-ip>:3000
and log in with the password the installer shows on its final page. To change it, edit
web-password and re-run the task: schtasks /run /tn PunktfunkWeb.
Rebuild + restart the console (dev box)
powershell -ExecutionPolicy Bypass -File scripts\windows\build-web.ps1
bun install && bun run build, installs the externalized server deps into .output/server
(with the @unom .npmrc), then restarts the PunktfunkWeb task and checks :3000/login. Use
this to iterate on the console against an installed host — web-setup.ps1 (or a fresh install) is
what creates the task in the first place.
Typical flow after pulling new code
git pull
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-host.ps1
powershell -ExecutionPolicy Bypass -File scripts\windows\build-web.ps1