Commit Graph
5 Commits
Author SHA1 Message Date
EdnunpandClaude Opus 4.8 4e15451e1d Service owns its binaries + is stoppable without admin; installer offers the service
The service was registered to run from wherever it was installed FROM (Environment
.ProcessPath), so installing from a dev/test folder pinned it there: it locked those
files (blocking every rebuild) and, for a real user installing from the app folder,
would lock the app's own binaries and break the auto-updater. Stopping it also needed
admin, so only the app's UAC-prompting Service menu could do it.

Fixes:
- The service now installs its OWN copy of the program into ProgramData\RemSound\
  service\bin and is registered to run from there. Never touches the install/dev
  folder again. CopyProgramTo copies the exe + DLLs + runtimes + default sounds but
  excludes user-state folders; uninstall removes the bin copy.
- Install grants Authenticated Users start/stop/query on the service (sc sdset, ACE
  merged into the existing DACL) so it can be stopped with a plain `sc stop
  RemSoundService` or the Service menu -- no admin, no app. Pure SDDL-amend helper is
  unit-tested (placement + idempotency).
- The app installer now asks, after install, whether to also install the service
  (optional, its own UAC step; declining is fine -- Service menu installs it later).
- deploy-test.ps1: only a copy running FROM the publish folder locks its binaries, so
  only that forces a sounds-only deploy. The service (ProgramData) and an installed app
  no longer make the script silently skip the binary publish -- the bug that had us
  testing stale builds for rounds.

New self-test "Service self-contained install" (runs-from-own-bin, SDDL amend, copy
exclusions). Gate: 40/40.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:38:24 +01:00
EdnunpandClaude Opus 4.8 92ed477ddf Service: harden for unattended running (auto-restart, findable logs, resume)
Local checkpoint - NOT for public release. A "what else does a service need" pass.

- AUTO-RESTART ON CRASH: DoInstall now sets sc failure actions (restart 5s/10s/then 60s,
  reset daily). Without this a crashed service stays dead until reboot - fatal for an
  always-on streamer.
- FINDABLE LOGS: --run-service redirects the service's data dir to the machine-wide
  ProgramData\RemSound\service location, so its log sits next to its profile instead of
  buried in the SYSTEM account's AppData.
- POWER RESUME: the service handles OnPowerEvent and re-opens capture on wake (audio
  devices re-initialise after sleep; the device-change watcher usually catches it, but a
  resume doesn't always fire an endpoint change, so we re-open explicitly).
- Start/stop already auto-log to the Windows Event Log via ServiceBase.

Test: "Service registration args" now also checks the audio-service dependency and the
auto-restart failure args. Gate 27/27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:43:33 +01:00
EdnunpandClaude Opus 4.8 91b3f0c1c1 Service: menu before Options + start-after-audio dependency
Local checkpoint - NOT for public release.

- Service menu now sits before Options in the menu bar (File / Record / Service /
  Options / Help), per Ed.
- The service is registered with depend= Audiosrv/AudioEndpointBuilder, so Windows
  starts it the instant the audio services are ready at boot (before login) - the
  earliest point WASAPI capture can find any audio. It CANNOT start before the audio
  services (there'd be no endpoints to capture, and no sound exists before audio is up),
  so this is the earliest useful start. DoInstall now uses the single BuildCreateArgs
  source of truth.

Gate 25/25.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 20:34:34 +01:00
EdnunpandClaude Opus 4.8 f4551517e5 Service: config dialog + Service menu
Local checkpoint - NOT for public release.

- ServiceProfileDialog: modal 3-tab editor (Audio send / Audio profile / Connectivity)
  reusing the house controls, with a Save and Close / Cancel / Additional options
  button row. Send-only: send-mode chooser + WASAPI outputs/apps + inputs (no "Send
  my audio" toggle, no receive, no ASIO); codec/rate/lock-to-clock; peers add/remove +
  a Set password button. Additional options sub-dialog = play connect/disconnect sound
  + enable service logging. Edits a Profile clone; returns it on OK.
- Service menu in MainForm: status line + Configure / Install / Uninstall / Start / Stop,
  items enabled per live state on drop-down. Install/uninstall confirm then elevate.
  Configure saves the reserved service profile, points AppConfig at it, stores the
  machine-wide logging choice, and restarts a running service to pick up edits.
- ProfileStore.ReservedServiceProfileTitle ("RemSound service"): the service profile
  lives with normal profiles (so the service Loads it) but ListProfileTitles hides it
  from every picker. ServiceControl reuses that single constant.
- Self-test: the service dialog is now in the accessibility audit (constructs cleanly,
  unique mnemonics, all controls named). Gate 20/20.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:27:37 +01:00
EdnunpandClaude Opus 4.8 5dbbe4dd71 Service: --run-service host + registration CLI (install/uninstall/start/stop)
Local checkpoint - NOT for public release.

- RemSoundService (ServiceBase): hosts ServiceSendHost.RunLoop on a worker thread,
  OnStop cancels + joins. Added System.ServiceProcess.ServiceController package.
- ServiceControl: install (sc.exe create, auto-start, careful binPath quoting) /
  uninstall (stop + delete) / start / stop / status. Status query is unprivileged
  (menu can poll it); the mutating verbs self-elevate via ShellExecute runas.
- Program.cs: early guards for --run-service (blocks in the SCM dispatcher) and the
  one-shot elevated verbs, before the single-instance lock (the service is a
  separate role and must never take the interactive lock).
- Self-test "Service registration args" verifies the sc create binPath quoting
  survives a spaced exe path. Gate 20/20.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:19:01 +01:00