diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index d3f44530c..0fb6e2b3c 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -256,6 +256,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public bool EnableUpdateLog { get; set; }
public bool StartFlowLauncherOnSystemStartup { get; set; } = false;
+ public bool UseLogonTaskForStartup { get; set; } = false;
public bool HideOnStartup { get; set; } = true;
bool _hideNotifyIcon { get; set; }
public bool HideNotifyIcon
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 952ca70c4..8374fc9fe 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -136,7 +136,14 @@ namespace Flow.Launcher
{
try
{
- Helper.AutoStartup.Enable();
+ if (_settings.UseLogonTaskForStartup)
+ {
+ Helper.AutoStartup.EnableViaLogonTask();
+ }
+ else
+ {
+ Helper.AutoStartup.EnableViaRegistry();
+ }
}
catch (Exception e)
{
diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj
index f8ace91f8..0baa1bef5 100644
--- a/Flow.Launcher/Flow.Launcher.csproj
+++ b/Flow.Launcher/Flow.Launcher.csproj
@@ -104,6 +104,7 @@
+
diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs
index 4bff30caf..c5e20504b 100644
--- a/Flow.Launcher/Helper/AutoStartup.cs
+++ b/Flow.Launcher/Helper/AutoStartup.cs
@@ -1,18 +1,31 @@
using System;
+using System.IO;
+using System.Linq;
+using System.Security.Principal;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Logger;
using Microsoft.Win32;
+using Microsoft.Win32.TaskScheduler;
namespace Flow.Launcher.Helper;
public class AutoStartup
{
private const string StartupPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
+ private const string LogonTaskName = $"{Constant.FlowLauncher} Startup";
+ private const string LogonTaskDesc = $"{Constant.FlowLauncher} Auto Startup";
public static bool IsEnabled
{
get
{
+ // Check if logon task is enabled
+ if (CheckLogonTask())
+ {
+ return true;
+ }
+
+ // Check if registry is enabled
try
{
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
@@ -28,12 +41,74 @@ public class AutoStartup
}
}
- public static void Disable()
+ private static bool CheckLogonTask()
+ {
+ using var taskService = new TaskService();
+ var task = taskService.RootFolder.AllTasks.FirstOrDefault(t => t.Name == LogonTaskName);
+ if (task != null)
+ {
+ try
+ {
+ // Check if the action is the same as the current executable path
+ var action = task.Definition.Actions.FirstOrDefault()!.ToString().Trim();
+ if (!Constant.ExecutablePath.Equals(action, StringComparison.OrdinalIgnoreCase) && !File.Exists(action))
+ {
+ UnscheduleLogonTask();
+ ScheduleLogonTask();
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ Log.Error("AutoStartup", $"Failed to check logon task: {e}");
+ }
+ }
+
+ return false;
+ }
+
+ public static void DisableViaLogonTaskAndRegistry()
+ {
+ Disable(true);
+ Disable(false);
+ }
+
+ public static void EnableViaLogonTask()
+ {
+ Enable(true);
+ }
+
+ public static void EnableViaRegistry()
+ {
+ Enable(false);
+ }
+
+ public static void ChangeToViaLogonTask()
+ {
+ Disable(false);
+ Enable(true);
+ }
+
+ public static void ChangeToViaRegistry()
+ {
+ Disable(true);
+ Enable(false);
+ }
+
+ private static void Disable(bool logonTask)
{
try
{
- using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
- key?.DeleteValue(Constant.FlowLauncher, false);
+ if (logonTask)
+ {
+ UnscheduleLogonTask();
+ }
+ else
+ {
+ using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
+ key?.DeleteValue(Constant.FlowLauncher, false);
+ }
}
catch (Exception e)
{
@@ -42,12 +117,19 @@ public class AutoStartup
}
}
- internal static void Enable()
+ private static void Enable(bool logonTask)
{
try
{
- using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
- key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
+ if (logonTask)
+ {
+ ScheduleLogonTask();
+ }
+ else
+ {
+ using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
+ key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
+ }
}
catch (Exception e)
{
@@ -55,4 +137,54 @@ public class AutoStartup
throw;
}
}
+
+ private static bool ScheduleLogonTask()
+ {
+ using var td = TaskService.Instance.NewTask();
+ td.RegistrationInfo.Description = LogonTaskDesc;
+ td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name, Delay = TimeSpan.FromSeconds(2) });
+ td.Actions.Add(Constant.ExecutablePath);
+
+ if (IsCurrentUserIsAdmin())
+ {
+ td.Principal.RunLevel = TaskRunLevel.Highest;
+ }
+
+ td.Settings.StopIfGoingOnBatteries = false;
+ td.Settings.DisallowStartIfOnBatteries = false;
+ td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
+
+ try
+ {
+ TaskService.Instance.RootFolder.RegisterTaskDefinition(LogonTaskName, td);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Log.Error("AutoStartup", $"Failed to schedule logon task: {e}");
+ return false;
+ }
+ }
+
+ private static bool UnscheduleLogonTask()
+ {
+ using var taskService = new TaskService();
+ try
+ {
+ taskService.RootFolder.DeleteTask(LogonTaskName);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Log.Error("AutoStartup", $"Failed to unschedule logon task: {e}");
+ return false;
+ }
+ }
+
+ private static bool IsCurrentUserIsAdmin()
+ {
+ var identity = WindowsIdentity.GetCurrent();
+ var principal = new WindowsPrincipal(identity);
+ return principal.IsInRole(WindowsBuiltInRole.Administrator);
+ }
}
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index c66772c83..93b45df91 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -47,6 +47,8 @@
Portable Mode
Store all settings and user data in one folder (Useful when used with removable drives or cloud services).
Start Flow Launcher on system startup
+ Use logon task instead of startup entry for faster startup experience
+ After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler
Error setting launch on startup
Hide Flow Launcher when focus is lost
Do not show new version notifications
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
index 4e498ba23..dddaa99d4 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
@@ -42,9 +42,20 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
try
{
if (value)
- AutoStartup.Enable();
+ {
+ if (UseLogonTaskForStartup)
+ {
+ AutoStartup.EnableViaLogonTask();
+ }
+ else
+ {
+ AutoStartup.EnableViaRegistry();
+ }
+ }
else
- AutoStartup.Disable();
+ {
+ AutoStartup.DisableViaLogonTaskAndRegistry();
+ }
}
catch (Exception e)
{
@@ -54,6 +65,34 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
}
}
+ public bool UseLogonTaskForStartup
+ {
+ get => Settings.UseLogonTaskForStartup;
+ set
+ {
+ Settings.UseLogonTaskForStartup = value;
+
+ if (StartFlowLauncherOnSystemStartup)
+ {
+ try
+ {
+ if (UseLogonTaskForStartup)
+ {
+ AutoStartup.ChangeToViaLogonTask();
+ }
+ else
+ {
+ AutoStartup.ChangeToViaRegistry();
+ }
+ }
+ catch (Exception e)
+ {
+ Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
+ e.Message);
+ }
+ }
+ }
+ }
public List SearchWindowScreens { get; } =
DropdownDataGeneric.GetValues("SearchWindowScreen");
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
index 30e065b16..a80e618e8 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
@@ -36,6 +36,13 @@
OnContent="{DynamicResource enable}" />
+
+
+
+