86 lines
3.0 KiB
C#
86 lines
3.0 KiB
C#
using System.Runtime.InteropServices;
|
|
using CursorLang.Interop;
|
|
using CursorLang.Models;
|
|
using Windows.ApplicationModel;
|
|
|
|
namespace CursorLang.Services;
|
|
|
|
/// <summary>
|
|
/// Startup, arranged by whatever means the current build has.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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 <see cref="RegistryStartup"/>.
|
|
/// </remarks>
|
|
public sealed class StartupService : IStartupService
|
|
{
|
|
/// <summary>Matches TaskId in the package manifest.</summary>
|
|
private const string TaskId = "CursorLangStartup";
|
|
|
|
private readonly RegistryStartup _registry = new();
|
|
|
|
public async Task<StartupState> 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<StartupState> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>The state of a Windows task in the app's own terms.</summary>
|
|
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,
|
|
};
|
|
}
|