using System.Runtime.InteropServices; using CursorLang.Core.Interop; using CursorLang.Core.Models; using Windows.ApplicationModel; namespace CursorLang.Core.Services; /// /// Startup, arranged by whatever means the current build has. /// /// /// Startup used to be a scheduled task with the highest rights — otherwise an app /// that wanted administrator rights would not start from the startup folder. The /// app needs no such rights any more, and the two ways left are simpler. /// /// A package declares the task in its manifest, and Windows lists it for the user /// next to the rest under Settings — Apps — Startup. Turned off there, it can no /// longer be turned back on by the app. Outside a package the same setting is kept /// in the registry: see . /// public sealed class StartupService : IStartupService { /// Matches TaskId in the package manifest. private const string TaskId = "CursorLangStartup"; private readonly RegistryStartup _registry = new(); public async Task GetStateAsync() { if (!PackageIdentityNative.IsPackaged) { return _registry.GetState(); } try { StartupTask task = await StartupTask.GetAsync(TaskId); return Translate(task.State); } catch (Exception e) when (e is COMException or ArgumentException or InvalidOperationException) { // No task by that name in the manifest: that happens to a package put // together by hand. The setting simply will not show return StartupState.Unavailable; } } public async Task SetEnabledAsync(bool enabled) { if (!PackageIdentityNative.IsPackaged) { return _registry.SetEnabled(enabled); } try { StartupTask task = await StartupTask.GetAsync(TaskId); if (!enabled) { task.Disable(); return Translate(task.State); } // Windows answers with a state rather than with success: once the user // has forbidden startup, the ban stays return Translate(await task.RequestEnableAsync()); } catch (Exception e) when (e is COMException or ArgumentException or InvalidOperationException) { return StartupState.Unavailable; } } /// The state of a Windows task in the app's own terms. internal static StartupState Translate(StartupTaskState state) => state switch { StartupTaskState.Enabled => StartupState.Enabled, StartupTaskState.EnabledByPolicy => StartupState.EnabledByPolicy, StartupTaskState.Disabled => StartupState.Disabled, StartupTaskState.DisabledByUser => StartupState.DisabledByUser, StartupTaskState.DisabledByPolicy => StartupState.DisabledByPolicy, _ => StartupState.Unavailable, }; }