About box shows only the newest 5 releases (screen-reader crash fix)
The About box's release notes had accumulated the ENTIRE version history back to v1.0 — ~70 KB in a single TextBox — and reading a control value that size crashes some screen readers (user reports, 2026-08-11). The box now displays only the newest five version blocks via a pure trim (TrimToLastVersions), ending with a plain pointer to the full history on the GitHub releases page. The full constant stays in source as the archive. Gate: new step pins the trim logic on synthetic notes AND the real shipped text (exactly 5 versions, size well under the crashing range — 5,516 chars vs ~70,000) so the crash can't quietly return as releases accumulate. 73/73. Readme About section updated + MANUAL regenerated; 5.8 notes mention the change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1175,7 +1175,7 @@ A step-by-step record of every update is kept in a file called `updater.log` in
|
||||
|
||||
### The About dialog and release notes
|
||||
|
||||
To see which version you're on without checking for updates, open **Help → About RemSound** (Alt+H, A). The dialog shows the version number and the release notes for the version you're running, in a scrollable read-only box. Close (or Esc) dismisses it.
|
||||
To see which version you're on without checking for updates, open **Help → About RemSound** (Alt+H, A). The dialog shows the version number and the release notes for the newest five versions, in a scrollable read-only box — newest first, so what just changed is right at the top. Notes for every older version live on the RemSound releases page on GitHub. Close (or Esc) dismisses it.
|
||||
|
||||
## 21. Recording to a file
|
||||
|
||||
|
||||
@@ -15,3 +15,4 @@ This release fixes the cause and heals affected machines automatically:
|
||||
- The service's log files are readable from every account on the machine again, so you can always open them in Notepad if you need to look at one or send it in. (The service's settings stay protected as before.)
|
||||
- If a service action fails, the message now says what actually went wrong instead of showing a bare error code, and the reason is recorded in the service's own log.
|
||||
- The repair, and the folder protection itself, now always apply to the account that's actually using RemSound — even on PCs where a different account's password is typed at the administrator prompt.
|
||||
- The About box now shows the newest five releases instead of the entire version history, which had grown large enough to upset some screen readers. The full history stays here on the releases page.
|
||||
|
||||
+1
-1
@@ -1236,7 +1236,7 @@ Use whatever key combinations you prefer (for example Ctrl+Shift+Up / Ctrl+Shift
|
||||
|
||||
<h3>The About dialog and release notes</h3>
|
||||
|
||||
<p>To see which version you're on without checking for updates, open <strong>Help → About RemSound</strong> (Alt+H, A). The dialog shows the version number and the release notes for the version you're running, in a scrollable read-only box. Close (or Esc) dismisses it.</p>
|
||||
<p>To see which version you're on without checking for updates, open <strong>Help → About RemSound</strong> (Alt+H, A). The dialog shows the version number and the release notes for the newest five versions, in a scrollable read-only box — newest first, so what just changed is right at the top. Notes for every older version live on the RemSound releases page on GitHub. Close (or Esc) dismisses it.</p>
|
||||
|
||||
<h2 id="recording">21. Recording to a file</h2>
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ internal sealed class AboutDialog : Form
|
||||
|
||||
The service's log files are also readable again from every account on the machine, so you can always open them in Notepad if you're curious or need to send one in. And if a service action ever fails, the message now says what actually went wrong instead of just showing a bare error code.
|
||||
|
||||
This About box also went on a diet: it now shows the newest five releases instead of the whole history, which had grown large enough to upset some screen readers. The full history is on the RemSound releases page on GitHub.
|
||||
|
||||
RemSound v5.7
|
||||
|
||||
Stronger security, and it works with every version again.
|
||||
@@ -1348,6 +1350,35 @@ internal sealed class AboutDialog : Form
|
||||
on every control, the keyboard shortcuts, and the troubleshooting guide.
|
||||
""";
|
||||
|
||||
/// <summary>How many version blocks the About box actually displays. The full constant above is
|
||||
/// the archive; the box shows only the newest few. The complete history reached ~70 KB in one
|
||||
/// TextBox, and reading a control value that size crashes some screen readers (reported
|
||||
/// 2026-08-11) — the box's job is "what's new", not the whole biography.</summary>
|
||||
private const int ShownVersions = 5;
|
||||
|
||||
/// <summary>The full notes constant, exposed for the self-test that pins the About box's displayed
|
||||
/// size (the screen-reader-crash regression guard).</summary>
|
||||
internal static string ReleaseNotesForTest => ReleaseNotes;
|
||||
|
||||
/// <summary>Pure, testable: cut <paramref name="notes"/> after its first <paramref name="maxVersions"/>
|
||||
/// version blocks (lines starting "RemSound v"), appending a plain pointer to the full history.
|
||||
/// Notes with fewer blocks pass through unchanged.</summary>
|
||||
internal static string TrimToLastVersions(string notes, int maxVersions)
|
||||
{
|
||||
var count = 0;
|
||||
var lines = notes.Split('\n');
|
||||
for (var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (!lines[i].TrimEnd('\r').StartsWith("RemSound v", StringComparison.Ordinal)) continue;
|
||||
if (++count <= maxVersions) continue;
|
||||
return string.Join("\n", lines, 0, i).TrimEnd()
|
||||
+ "\r\n\r\nThat's the newest "
|
||||
+ maxVersions
|
||||
+ " releases. Notes for every version back to the beginning are on the RemSound releases page on GitHub.";
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
|
||||
public AboutDialog()
|
||||
{
|
||||
Text = "About RemSound";
|
||||
@@ -1377,7 +1408,7 @@ internal sealed class AboutDialog : Form
|
||||
Dock = DockStyle.Fill,
|
||||
ScrollBars = ScrollBars.Vertical,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
Text = ReleaseNotes,
|
||||
Text = TrimToLastVersions(ReleaseNotes, ShownVersions),
|
||||
AccessibleName = "Release notes (tab into and arrow to read)",
|
||||
};
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ internal static class SelfTest
|
||||
RunStep(results, "Service folder lockdown args (cross-user LPE hardening)", ServiceDirHardeningArgs);
|
||||
RunStep(results, "Service folder repair (reproduce wrong-owner lockout → detect → repair → verify)", ServiceAccessRepairLoop);
|
||||
RunStep(results, "Elevated verbs carry the real user (SID pass-through) + logs stay readable", ElevatedIdentityPassThrough);
|
||||
RunStep(results, "About box shows only the newest releases (screen-reader-safe size)", AboutBoxNotesTrimmed);
|
||||
RunStep(results, "Long-run hygiene (log rotation, crash-report cap, priority-mode scope)", LongRunHygiene);
|
||||
RunStep(results, "Service startup volume (boot-once decision + settings round-trip)", ServiceStartupVolume);
|
||||
RunStep(results, "Update install window (same-day, wraparound, retry timing)", UpdateInstallWindow);
|
||||
@@ -2921,6 +2922,33 @@ internal static class SelfTest
|
||||
return "identity travels by argument and only real user SIDs are trusted; logs readable by every account, read-only";
|
||||
}
|
||||
|
||||
/// <summary>The About box's release-notes text must stay small: the full history reached ~70 KB in
|
||||
/// one TextBox and reading a control value that size CRASHES some screen readers (reported
|
||||
/// 2026-08-11). The box shows only the newest five version blocks, with a pointer to the full
|
||||
/// history; this pins both the trim logic and the real shipped text's size so the crash can't
|
||||
/// quietly come back as releases accumulate.</summary>
|
||||
private static string? AboutBoxNotesTrimmed()
|
||||
{
|
||||
// The trim logic on synthetic notes: 7 blocks in, 5 out, pointer appended; fewer than the
|
||||
// limit passes through untouched.
|
||||
var synthetic = string.Join("\r\n\r\n", Enumerable.Range(1, 7).Select(i => $"RemSound v9.{i}\r\n\r\nNotes for release {i}."));
|
||||
var trimmed = AboutDialog.TrimToLastVersions(synthetic, 5);
|
||||
Check(trimmed.Split('\n').Count(l => l.TrimEnd('\r').StartsWith("RemSound v", StringComparison.Ordinal)) == 5,
|
||||
"seven version blocks must trim to exactly five");
|
||||
Check(trimmed.Contains("RemSound v9.5") && !trimmed.Contains("RemSound v9.6"),
|
||||
"the fifth-newest block stays, the sixth is cut");
|
||||
Check(trimmed.Contains("releases page"), "the cut must end with a pointer to the full history");
|
||||
Check(AboutDialog.TrimToLastVersions("RemSound v1.0\r\nOnly one.", 5) == "RemSound v1.0\r\nOnly one.",
|
||||
"notes with fewer blocks than the limit pass through unchanged");
|
||||
|
||||
// The REAL shipped text: exactly five versions shown, and small enough to be read safely.
|
||||
var shown = AboutDialog.TrimToLastVersions(AboutDialog.ReleaseNotesForTest, 5);
|
||||
var versions = shown.Split('\n').Count(l => l.TrimEnd('\r').StartsWith("RemSound v", StringComparison.Ordinal));
|
||||
Check(versions == 5, $"the shipped About text must show exactly 5 versions (got {versions})");
|
||||
Check(shown.Length < 10_000, $"the shipped About text must stay well under screen-reader-crashing size (got {shown.Length} chars)");
|
||||
return $"shipped About text: 5 versions, {shown.Length} chars (was ~70,000 — the screen-reader crash)";
|
||||
}
|
||||
|
||||
/// <summary>Issue #23 boot self-heal decision core. Scenario: at the boot lock screen the machine's
|
||||
/// speakers audibly play (Windows tune, NVDA) but a capture attached in the first seconds of boot
|
||||
/// taps an engine mix the logon-session audio was never wired into — the endpoint's own METER shows
|
||||
|
||||
Reference in New Issue
Block a user