Skip to content

Commit ef1cfd4

Browse files
committed
Reduce hangs and implement Restart Manager compliance (#30)
* Add Windows shutdown message handling (WM_QUERYENDSESSION/WM_ENDSESSION) * Register application for restart after Windows Updates * Implement graceful shutdown within 2 second timeout * Add SystemEvents.SessionEnding handler for logoff/shutdown * Add global exception handlers (Application.ThreadException, UnhandledException) * Wrap async void event handlers with try/catch to prevent crashes * Implement proper icon disposal with thread-safe locking * Add symbol image caching to reduce menu rendering overhead * Move process instance check off UI thread * Clear caches on theme changes to prevent memory leaks Complies with Microsoft Restart Manager guidelines: - Responds to shutdown messages correctly - Saves state within timeout period - Registers for restart (no crash/hang restart) - Handles forced shutdown gracefully Fixes #30
1 parent d89b5e7 commit ef1cfd4

3 files changed

Lines changed: 292 additions & 103 deletions

File tree

Forms/SettingsForm.cs

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -169,24 +169,31 @@ private void DeleteMI_Click(object? sender, EventArgs e) {
169169
}
170170

171171
private async void setStartupCheckBox() {
172-
StartupTask startupTask = await StartupTask.GetAsync("StartCaffeinated");
173-
Debug.WriteLine("Startup is " + startupTask.State.ToString());
174-
175-
switch (startupTask.State) {
176-
case StartupTaskState.Disabled:
177-
// Task is disabled but can be enabled.
178-
StartupChkBox.Checked = false;
179-
break;
180-
case StartupTaskState.DisabledByUser:
181-
// Task is disabled and user must enable it manually.
182-
StartupChkBox.Checked = false;
183-
StartupChkBox.Enabled = false;
184-
185-
StartupChkBox.Text += "\nDisabled in Task Manager";
186-
break;
187-
case StartupTaskState.Enabled:
188-
StartupChkBox.Checked = true;
189-
break;
172+
try {
173+
StartupTask startupTask = await StartupTask.GetAsync("StartCaffeinated");
174+
Debug.WriteLine("Startup is " + startupTask.State.ToString());
175+
176+
switch (startupTask.State) {
177+
case StartupTaskState.Disabled:
178+
// Task is disabled but can be enabled.
179+
StartupChkBox.Checked = false;
180+
break;
181+
case StartupTaskState.DisabledByUser:
182+
// Task is disabled and user must enable it manually.
183+
StartupChkBox.Checked = false;
184+
StartupChkBox.Enabled = false;
185+
186+
StartupChkBox.Text += "\nDisabled in Task Manager";
187+
break;
188+
case StartupTaskState.Enabled:
189+
StartupChkBox.Checked = true;
190+
break;
191+
}
192+
}
193+
catch (Exception ex) {
194+
Debug.WriteLine($"Error checking startup state: {ex.Message}");
195+
// Disable checkbox if we can't determine state
196+
StartupChkBox.Enabled = false;
190197
}
191198
}
192199

@@ -205,17 +212,28 @@ private void DefaultDurationBox_SelectedIndexChanged(object sender,EventArgs e)
205212
}
206213

207214
private async void StartupChkBox_CheckedChanged(object sender, EventArgs e) {
208-
StartupTask startupTask = await StartupTask.GetAsync("StartCaffeinated");
209-
210-
switch (StartupChkBox.Checked) {
211-
case true:
212-
StartupTaskState newState = await startupTask.RequestEnableAsync();
213-
Debug.WriteLine("Request to enable startup, result = {0}", newState);
214-
break;
215-
case false:
216-
startupTask.Disable();
217-
Debug.WriteLine("Disabled startup task");
218-
break;
215+
try {
216+
StartupTask startupTask = await StartupTask.GetAsync("StartCaffeinated");
217+
218+
switch (StartupChkBox.Checked) {
219+
case true:
220+
StartupTaskState newState = await startupTask.RequestEnableAsync();
221+
Debug.WriteLine("Request to enable startup, result = {0}", newState);
222+
break;
223+
case false:
224+
startupTask.Disable();
225+
Debug.WriteLine("Disabled startup task");
226+
break;
227+
}
228+
}
229+
catch (Exception ex) {
230+
Debug.WriteLine($"Error changing startup state: {ex.Message}");
231+
MessageBox.Show(
232+
$"Could not change startup setting: {ex.Message}",
233+
"Caffeinated",
234+
MessageBoxButtons.OK,
235+
MessageBoxIcon.Warning
236+
);
219237
}
220238
}
221239

Helpers/NativeMethods.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,14 @@ internal static class NativeMethods {
88
public const uint ES_CONTINUOUS = 0x80000000;
99
public const uint ES_SYSTEM_REQUIRED = 0x00000001;
1010
public const uint ES_DISPLAY_REQUIRED = 0x00000002;
11+
12+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
13+
public static extern int RegisterApplicationRestart(
14+
string? pwzCommandline,
15+
int dwFlags);
16+
17+
public const int RESTART_NO_CRASH = 1;
18+
public const int RESTART_NO_HANG = 2;
19+
public const int RESTART_NO_PATCH = 4;
20+
public const int RESTART_NO_REBOOT = 8;
1121
}

0 commit comments

Comments
 (0)