refactor(host/windows): clean up DDA path + add a proper Windows service
Final cleanup after the DDA-parity work, plus an end-user service to replace the PsExec/VBS/scheduled-task launch chain. Cleanup (behavior-preserving): - sudovda.rs: drop the dead legacy GDI isolate_displays/restore_displays (CCD is the sole isolation path), the always-empty Monitor.isolated field, and the vestigial reassert_isolation + PUNKTFUNK_ISOLATE_DISPLAYS knob; fix stale comments. - dxgi.rs: downgrade leftover debug warns/infos (DuplicateOutput1 retry, FALLBACKS, hook-hits, AcquireNextFrame idle timeout) to debug!; remove the PUNKTFUNK_NO_CURSOR per-frame test knob. Windows service (src/service.rs, `punktfunk-host service`): - SCM supervisor (windows-service crate) that duplicates its LocalSystem token, retargets it to the active console session, and CreateProcessAsUserW's the host there (Sunshine/Apollo model) — relaunching on exit and console session switch, inside a kill-on-close job object so a service crash never orphans the host. - install/uninstall/start/stop/status subcommands: one elevated `service install` registers an auto-start LocalSystem service + firewall rules + a default host.env. - Config moves to %ProgramData%\punktfunk\host.env; config_dir() now resolves to %ProgramData%\punktfunk on Windows (replacing the APPDATA=C:\Users\Public hack), with a PUNKTFUNK_CONFIG_DIR override. Logs land in %ProgramData%\punktfunk\logs\. - merged_env_block (shared with the WGC helper) now also carries RUST_LOG. - docs/windows-service.md + scripts/windows/host.env.example; windows-host.md updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -152,11 +152,12 @@ unsafe fn no_inherit(h: HANDLE) {
|
||||
let _ = SetHandleInformation(h, HANDLE_FLAG_INHERIT.0, HANDLE_FLAGS(0));
|
||||
}
|
||||
|
||||
/// Build the helper's environment block: the user's block (so DLL/PATH/SystemRoot resolve) with this
|
||||
/// (host) process's `PUNKTFUNK_*` vars overlaid, so the helper encodes with the SAME settings the
|
||||
/// host runs with (`PUNKTFUNK_ENCODER=nvenc`, `PUNKTFUNK_ZEROCOPY`, …) instead of the user shell's.
|
||||
/// Returns a UTF-16, double-null-terminated block suitable for `CREATE_UNICODE_ENVIRONMENT`.
|
||||
unsafe fn merged_env_block(user_block: *const u16) -> Vec<u16> {
|
||||
/// Build a child environment block: the target session's block (so DLL/PATH/SystemRoot resolve) with
|
||||
/// this process's `PUNKTFUNK_*` vars overlaid, so the child runs with the SAME settings this process
|
||||
/// has (`PUNKTFUNK_ENCODER=nvenc`, `PUNKTFUNK_ZEROCOPY`, …) instead of the target shell's. Returns a
|
||||
/// UTF-16, double-null-terminated block suitable for `CREATE_UNICODE_ENVIRONMENT`. Shared by the WGC
|
||||
/// helper spawn (here) and the Windows service launching the host into the active session.
|
||||
pub(crate) unsafe fn merged_env_block(user_block: *const u16) -> Vec<u16> {
|
||||
// Parse the user block ("VAR=VALUE\0" … "\0") into entries.
|
||||
let mut entries: Vec<String> = Vec::new();
|
||||
if !user_block.is_null() {
|
||||
@@ -174,9 +175,10 @@ unsafe fn merged_env_block(user_block: *const u16) -> Vec<u16> {
|
||||
p = p.offset(len + 1);
|
||||
}
|
||||
}
|
||||
// Drop any PUNKTFUNK_* the user block carried, then overlay this process's PUNKTFUNK_* vars.
|
||||
entries.retain(|e| !e.split('=').next().unwrap_or("").starts_with("PUNKTFUNK_"));
|
||||
for (k, v) in std::env::vars().filter(|(k, _)| k.starts_with("PUNKTFUNK_")) {
|
||||
// Overlay "our" settings — PUNKTFUNK_* and RUST_LOG — dropping whatever the target block had.
|
||||
let is_ours = |k: &str| k.starts_with("PUNKTFUNK_") || k == "RUST_LOG";
|
||||
entries.retain(|e| !is_ours(e.split('=').next().unwrap_or("")));
|
||||
for (k, v) in std::env::vars().filter(|(k, _)| is_ours(k)) {
|
||||
entries.push(format!("{k}={v}"));
|
||||
}
|
||||
// Serialize back to a UTF-16 double-null-terminated block.
|
||||
|
||||
Reference in New Issue
Block a user