Support running application under non-admin mode & Show UAC dialogs when running admin mode when application is under admin mode

This commit is contained in:
Jack251970 2025-05-22 19:54:42 +08:00
parent 369ed86d1d
commit 10d379f350
4 changed files with 79 additions and 36 deletions

View file

@ -97,5 +97,7 @@
<system:String x:Key="flowlauncher_plugin_program_disable_dlgtitle_success_message">Successfully disabled this program from displaying in your query</system:String>
<system:String x:Key="flowlauncher_plugin_program_run_as_administrator_not_supported_message">This app is not intended to be run as administrator</system:String>
<system:String x:Key="flowlauncher_plugin_program_run_failed">Unable to run {0}</system:String>
<system:String x:Key="flowlauncher_plugin_program_user_account_control_title">User Account Control</system:String>
<system:String x:Key="flowlauncher_plugin_program_user_account_control_subtitle">Do you want to allow this app to make changes to your device?</system:String>
</ResourceDictionary>

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
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 @@ namespace Flow.Launcher.Plugin.Program
internal static PluginInitContext Context { get; private set; }
internal static bool IsAdmin = IsAdministrator();
private static readonly List<Result> emptyResults = new();
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
@ -459,5 +462,12 @@ namespace Flow.Launcher.Plugin.Program
{
Win32.Dispose();
}
private static bool IsAdministrator()
{
using var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
}

View file

@ -4,17 +4,17 @@ using System.Diagnostics;
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 @@ namespace Flow.Launcher.Plugin.Program.Programs
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 @@ namespace Flow.Launcher.Plugin.Program.Programs
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 @@ namespace Flow.Launcher.Plugin.Program.Programs
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)

View file

@ -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 @@ namespace Flow.Launcher.Plugin.Program.Programs
// 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 @@ namespace Flow.Launcher.Plugin.Program.Programs
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<Result> ContextMenus(IPublicAPI api)
{
@ -228,7 +259,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
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 @@ namespace Flow.Launcher.Plugin.Program.Programs
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;
},