From 7549bba2930607bbaea90fab795ce2bd8a8f48f5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 18:43:41 +0800 Subject: [PATCH 01/51] Add administrator mode check --- Flow.Launcher.Infrastructure/Win32Helper.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 783ade14ebe..346a86ab624 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Runtime.InteropServices; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -753,5 +754,16 @@ private static bool TryGetNotoFont(string langKey, out string notoFont) } #endregion + + #region Administrator Mode + + public static bool IsAdministrator() + { + using var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + + #endregion } } From 369ed86d1d8e68746b28634d75f12a2d4bead828 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 18:44:01 +0800 Subject: [PATCH 02/51] Add administrator text in tray icon --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/MainWindow.xaml.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index f233a30d56f..2abeb28f505 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -46,6 +46,7 @@ Position Reset Reset search window position Type here to search + (Admin) Settings diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index bb29d78e5e8..470b25f93e4 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -595,9 +595,13 @@ private void SoundPlay() private void InitializeNotifyIcon() { + var text = Win32Helper.IsAdministrator() ? + Constant.FlowLauncherFullName + " " + App.API.GetTranslation("admin") : + Constant.FlowLauncherFullName; + _notifyIcon = new NotifyIcon { - Text = Constant.FlowLauncherFullName, + Text = text, Icon = Constant.Version == "1.0.0" ? Properties.Resources.dev : Properties.Resources.app, Visible = !_settings.HideNotifyIcon }; From 10d379f350a6f94a37b177368301cdc1e2415395 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 19:54:42 +0800 Subject: [PATCH 03/51] Support running application under non-admin mode & Show UAC dialogs when running admin mode when application is under admin mode --- .../Languages/en.xaml | 2 + Plugins/Flow.Launcher.Plugin.Program/Main.cs | 10 +++ .../Programs/UWPPackage.cs | 30 +++++--- .../Programs/Win32.cs | 73 ++++++++++++------- 4 files changed, 79 insertions(+), 36 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml index e551a7dcb4e..cd1cc051c4f 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml @@ -97,5 +97,7 @@ Successfully disabled this program from displaying in your query This app is not intended to be run as administrator Unable to run {0} + User Account Control + Do you want to allow this app to make changes to your device? diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index d2884599467..f220190e253 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; @@ -32,6 +33,8 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I internal static PluginInitContext Context { get; private set; } + internal static bool IsAdmin = IsAdministrator(); + private static readonly List emptyResults = new(); private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 }; @@ -459,5 +462,12 @@ public void Dispose() { Win32.Dispose(); } + + private static bool IsAdministrator() + { + using var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs index cb33250e15e..182f3fed537 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs @@ -4,17 +4,17 @@ using System.IO; using System.Linq; using System.Security.Principal; +using System.Threading.Channels; using System.Threading.Tasks; +using System.Windows.Input; using System.Windows.Media.Imaging; -using Windows.ApplicationModel; -using Windows.Management.Deployment; +using System.Xml; using Flow.Launcher.Plugin.Program.Logger; using Flow.Launcher.Plugin.SharedModels; -using System.Threading.Channels; -using System.Xml; -using Windows.ApplicationModel.Core; -using System.Windows.Input; using MemoryPack; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Core; +using Windows.Management.Deployment; namespace Flow.Launcher.Plugin.Program.Programs { @@ -454,7 +454,9 @@ public Result Result(string query, IPublicAPI api) bool elevated = e.SpecialKeyState.ToModifierKeys() == (ModifierKeys.Control | ModifierKeys.Shift); bool shouldRunElevated = elevated && CanRunElevated; - _ = Task.Run(() => Launch(shouldRunElevated)).ConfigureAwait(false); + + Launch(shouldRunElevated); + if (elevated && !shouldRunElevated) { var title = api.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_error"); @@ -497,7 +499,8 @@ public List ContextMenus(IPublicAPI api) Title = api.GetTranslation("flowlauncher_plugin_program_run_as_administrator"), Action = c => { - _ = Task.Run(() => Launch(true)).ConfigureAwait(false); + Launch(true); + return true; }, IcoPath = "Images/cmd.png", @@ -510,12 +513,17 @@ public List ContextMenus(IPublicAPI api) private void Launch(bool elevated = false) { - string command = "shell:AppsFolder\\" + UserModelId; + var command = "shell:AppsFolder\\" + UserModelId; command = Environment.ExpandEnvironmentVariables(command.Trim()); - var info = new ProcessStartInfo(command) { UseShellExecute = true, Verb = elevated ? "runas" : "" }; + var info = new ProcessStartInfo() + { + FileName = command, + UseShellExecute = true, + Verb = elevated ? "runas" : "" + }; - Main.StartProcess(Process.Start, info); + _ = Task.Run(() => Main.StartProcess(Process.Start, info)).ConfigureAwait(false); } internal static bool IfAppCanRunElevated(XmlNode appNode) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index a87b002d414..3dd7ec0128c 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -1,21 +1,22 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Security; using System.Text; +using System.Threading.Channels; using System.Threading.Tasks; -using Microsoft.Win32; +using System.Windows; +using System.Windows.Input; using Flow.Launcher.Plugin.Program.Logger; +using Flow.Launcher.Plugin.Program.Views.Models; using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Plugin.SharedModels; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading.Channels; -using Flow.Launcher.Plugin.Program.Views.Models; using IniParser; -using System.Windows.Input; using MemoryPack; +using Microsoft.Win32; namespace Flow.Launcher.Plugin.Program.Programs { @@ -196,15 +197,7 @@ public Result Result(string query, IPublicAPI api) // Ctrl + Shift + Enter to run as admin bool runAsAdmin = c.SpecialKeyState.ToModifierKeys() == (ModifierKeys.Control | ModifierKeys.Shift); - var info = new ProcessStartInfo - { - FileName = FullPath, - WorkingDirectory = ParentDirectory, - UseShellExecute = true, - Verb = runAsAdmin ? "runas" : "", - }; - - _ = Task.Run(() => Main.StartProcess(Process.Start, info)); + Launch(runAsAdmin); return true; } @@ -213,6 +206,44 @@ public Result Result(string query, IPublicAPI api) return result; } + private void Launch(bool elevated = false) + { + var info = new ProcessStartInfo + { + FileName = FullPath, + WorkingDirectory = ParentDirectory, + UseShellExecute = true, + Verb = elevated ? "runas" : "", + }; + + if (Main.IsAdmin) + { + if (elevated) + { + // Since we are already elevated, we need to create UAC dialog manually + if (Main.Context.API.ShowMsgBox( + Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_subtitle"), + Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_title"), + MessageBoxButton.YesNo) != MessageBoxResult.Yes) + { + return; + } + } + else + { + // Use explorer.exe as workaround to start process as standard user + info = new ProcessStartInfo + { + FileName = "explorer.exe", + Arguments = $"\"{FullPath}\"", + WorkingDirectory = ParentDirectory, + UseShellExecute = true, + }; + } + } + + _ = Task.Run(() => Main.StartProcess(Process.Start, info)).ConfigureAwait(false); ; + } public List ContextMenus(IPublicAPI api) { @@ -228,7 +259,7 @@ public List ContextMenus(IPublicAPI api) FileName = FullPath, WorkingDirectory = ParentDirectory, UseShellExecute = true }; - _ = Task.Run(() => Main.StartProcess(ShellCommand.RunAsDifferentUser, info)); + _ = Task.Run(() => Main.StartProcess(ShellCommand.RunAsDifferentUser, info)).ConfigureAwait(false);; return true; }, @@ -240,15 +271,7 @@ public List ContextMenus(IPublicAPI api) Title = api.GetTranslation("flowlauncher_plugin_program_run_as_administrator"), Action = c => { - var info = new ProcessStartInfo - { - FileName = FullPath, - WorkingDirectory = ParentDirectory, - Verb = "runas", - UseShellExecute = true - }; - - _ = Task.Run(() => Main.StartProcess(Process.Start, info)); + Launch(true); return true; }, From 484f91c52d2de6100661c6dcf40cefc0729a5dd2 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 20:26:41 +0800 Subject: [PATCH 04/51] Improve UAC dialog --- .../Languages/en.xaml | 1 + .../Programs/Win32.cs | 5 +- .../UACDialog.xaml | 154 ++++++++++++++++++ .../UACDialog.xaml.cs | 87 ++++++++++ 4 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Program/UACDialog.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.Program/UACDialog.xaml.cs diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml index cd1cc051c4f..e3eeb4e91a5 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml @@ -99,5 +99,6 @@ Unable to run {0} User Account Control Do you want to allow this app to make changes to your device? + Program location: {0} diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 3dd7ec0128c..8cf1f77dad5 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -221,10 +221,7 @@ private void Launch(bool elevated = false) if (elevated) { // Since we are already elevated, we need to create UAC dialog manually - if (Main.Context.API.ShowMsgBox( - Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_subtitle"), - Main.Context.API.GetTranslation("flowlauncher_plugin_program_user_account_control_title"), - MessageBoxButton.YesNo) != MessageBoxResult.Yes) + if (UACDialog.Show(IcoPath, Name, FullPath) != MessageBoxResult.Yes) { return; } diff --git a/Plugins/Flow.Launcher.Plugin.Program/UACDialog.xaml b/Plugins/Flow.Launcher.Plugin.Program/UACDialog.xaml new file mode 100644 index 00000000000..d619f47654d --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/UACDialog.xaml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +