Prevent Screen Saver is a single-project .NET 10 Windows Forms application. Its source is organized into focused, single-responsibility classes that are composed insideDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/proteo5/Prevent-Screen-Saver/llms.txt
Use this file to discover all available pages before exploring further.
Form1, which acts as the central coordinator between the tray UI and the underlying services. This page documents the repository layout, the purpose of each class, and the key internal types exposed by the service layer.
Repository Layout
PreventScreenSaver.csproj) targets net10.0-windows, uses Windows Forms (<UseWindowsForms>true</UseWindowsForms>), and outputs a Windows executable (<OutputType>WinExe</OutputType>).
Key Classes
Program — Entry Point
Program.cs is the application entry point. Before launching the Windows Forms message loop, it acquires a named Mutex to enforce the single-instance constraint. If another instance of the app is already running, Main() returns immediately without showing any window or error.
Form1 — Main Window and Tray Coordinator
Form1.cs is the central hub of the application. It owns the tray icon, the context menu, and the main status window. On construction, it loads persisted settings, initializes the hotkey submenu, restores the last protection state, and synchronizes all UI elements.
Key responsibilities include:
- Routing user actions — tray left-click, tray double-click, menu items (Activate, Deactivate, Open, Start with Windows, Hotkey, Help, About, Exit), and the main window button all converge on shared
ActivateProtection(),DeactivateProtection(), andToggleProtection()methods. - Handling
WM_HOTKEYmessages —WndProcintercepts the Windows hotkey message and routes it to the same toggle path used by the tray controls. - Keeping state in sync —
UpdateUiState()updates the tray icon, tray tooltip, and window title in a single call whenever protection state changes. - Cleanup on close — when the user selects Exit, protection is stopped, the hotkey is unregistered, settings are persisted, and the tray icon is hidden before the form closes.
Closing the main window does not exit the application. The
OnFormClosing override cancels the close event and hides the window to the tray unless exitRequested is true, which is only set by the Exit menu item.ScreenSaverProtectionService — Windows API Wrapper
This service wraps the SetThreadExecutionState P/Invoke call and exposes a clean interface to Form1.
| State | Flags passed to SetThreadExecutionState |
|---|---|
| Protection active | ES_CONTINUOUS | ES_DISPLAY_REQUIRED |
| Protection inactive | ES_CONTINUOUS only |
StartProtection() returns false if the API call returns zero, allowing Form1 to surface a visible error message rather than silently failing.
GlobalHotkeyService — Hotkey Lifecycle Manager
GlobalHotkeyService wraps RegisterHotKey and UnregisterHotKey from user32.dll and implements IDisposable to guarantee cleanup.
TryRegister fails, it returns the Win32 error code in errorMessage so Form1 can log the failure and show a tray notification. The service calls Unregister() automatically before any new registration attempt, preventing stale registrations from persisting across preset changes.
HotkeyModifiers Enum
The
NoRepeat flag is always OR’d with the selected preset’s modifiers when registering the hotkey. This prevents the toggle action from firing repeatedly while the user holds the key combination down, which would cause the protection state to flip back and forth.HotkeyPresets — Built-in Shortcut Registry
HotkeyPresets is a static class that defines five built-in key combinations. The full list is:
| Preset ID | Display Name | Modifiers | Key |
|---|---|---|---|
ctrl-alt-p | Ctrl+Alt+P | Control + Alt | P |
ctrl-shift-f12 | Ctrl+Shift+F12 | Control + Shift | F12 |
ctrl-shift-f11 | Ctrl+Shift+F11 | Control + Shift | F11 |
ctrl-shift-f10 | Ctrl+Shift+F10 | Control + Shift | F10 |
ctrl-shift-f9 | Ctrl+Shift+F9 | Control + Shift | F9 |
All (all five presets as IReadOnlyList<HotkeyPreset>), Default (Ctrl+Alt+P), and Resolve(id), which falls back to the default for any unknown or empty ID — ensuring invalid stored settings never cause a crash.
AppSettingsStore — Settings Persistence
Settings are serialized as indented JSON to %LocalAppData%\PreventScreenSaver\settings.json using System.Text.Json. The stored fields are:
| Field | Type | Default |
|---|---|---|
StartMinimized | bool | true |
LastProtectionActive | bool | false |
HotkeyEnabled | bool | true |
HotkeyPresetId | string | "ctrl-alt-p" |
AppSettingsStore.Load() returns a fresh instance with defaults if the file does not yet exist. Save() creates the directory if needed before writing, so the file path is always safe to write on first run.
StartupRegistrationService — Windows Startup Integration
This service reads and writes the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run registry key to control whether the application launches at Windows login. No administrator rights are required — the key is in the current-user hive.
IsEnabled() checks that the stored value exactly matches the current executable path (case-insensitive). SetEnabled(true) writes the path; SetEnabled(false) removes the value without throwing if it is already absent.
DiagnosticsLog — Plain-Text Log
DiagnosticsLog appends timestamped entries to %LocalAppData%\PreventScreenSaver\log.txt. Each line is formatted as:
TrayIconFactory — Programmatic Icon Generation
TrayIconFactory creates both tray icon states at runtime using System.Drawing — no embedded icon files are required.
Idle Icon
A grey circle (
RGB 97, 110, 128) with two vertical white pause bars. Shown when protection is inactive.Active Icon
A green circle (
RGB 32, 158, 97) with a white checkmark. Shown when SetThreadExecutionState is holding the active state.GetHicon(), cloned from a temporary Icon handle, and freed with DestroyIcon to avoid handle leaks.
AboutForm / HelpForm — In-App Dialogs
These are lightweight Windows Forms dialogs opened from the tray context menu. They are positioned relative to the main window (or the cursor position if the window is not visible) using a ShowDialogCenteredOnMainWindow helper in Form1. Both are instantiated fresh on each open and disposed when closed.
Service Dependency Map
All services are instantiated directly byForm1 as private readonly fields. There is no IoC container — the composition is explicit and visible at the top of Form1.cs:
Form1 is the only class that holds references to multiple services. Each service class has no knowledge of the others — all coordination flows through Form1.