diff --git a/Plugins/Wox.Plugin.Program/Images/user.png b/Plugins/Wox.Plugin.Program/Images/user.png new file mode 100644 index 0000000000..2d45c1ee91 Binary files /dev/null and b/Plugins/Wox.Plugin.Program/Images/user.png differ diff --git a/Plugins/Wox.Plugin.Program/Languages/en.xaml b/Plugins/Wox.Plugin.Program/Languages/en.xaml index bb218887c4..b7202d590f 100644 --- a/Plugins/Wox.Plugin.Program/Languages/en.xaml +++ b/Plugins/Wox.Plugin.Program/Languages/en.xaml @@ -31,6 +31,7 @@ Successfully updated file suffixes File suffixes can't be empty + Run As Different User Run As Administrator Open containing folder Disable this program from displaying diff --git a/Plugins/Wox.Plugin.Program/Main.cs b/Plugins/Wox.Plugin.Program/Main.cs index a37e9f2028..a135d1e805 100644 --- a/Plugins/Wox.Plugin.Program/Main.cs +++ b/Plugins/Wox.Plugin.Program/Main.cs @@ -191,12 +191,12 @@ namespace Wox.Plugin.Program ); } - public static bool StartProcess(ProcessStartInfo info) + public static bool StartProcess(Func runProcess, ProcessStartInfo info) { bool hide; try { - Process.Start(info); + runProcess(info); hide = true; } catch (Exception) diff --git a/Plugins/Wox.Plugin.Program/Programs/UWP.cs b/Plugins/Wox.Plugin.Program/Programs/UWP.cs index 2c608807b4..e73371cd14 100644 --- a/Plugins/Wox.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Wox.Plugin.Program/Programs/UWP.cs @@ -320,7 +320,7 @@ namespace Wox.Plugin.Program.Programs Title = api.GetTranslation("wox_plugin_program_open_containing_folder"), Action = _ => { - var hide = Main.StartProcess(new ProcessStartInfo(Package.Location)); + var hide = Main.StartProcess(Process.Start, new ProcessStartInfo(Package.Location)); return hide; }, IcoPath = "Images/folder.png" diff --git a/Plugins/Wox.Plugin.Program/Programs/Win32.cs b/Plugins/Wox.Plugin.Program/Programs/Win32.cs index 36e08a3c46..ee34328d9a 100644 --- a/Plugins/Wox.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Wox.Plugin.Program/Programs/Win32.cs @@ -6,10 +6,12 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security; using System.Text; +using System.Threading.Tasks; using Microsoft.Win32; using Shell; using Wox.Infrastructure; using Wox.Plugin.Program.Logger; +using Wox.Plugin.SharedCommands; namespace Wox.Plugin.Program.Programs { @@ -64,7 +66,7 @@ namespace Wox.Plugin.Program.Programs FileName = FullPath, WorkingDirectory = ParentDirectory }; - var hide = Main.StartProcess(info); + var hide = Main.StartProcess(Process.Start, info); return hide; } }; @@ -91,6 +93,19 @@ namespace Wox.Plugin.Program.Programs { var contextMenus = new List { + new Result + { + Title = api.GetTranslation("wox_plugin_program_run_as_different_user"), + Action = _ => + { + var info = FullPath.SetProcessStartInfo(ParentDirectory); + + Task.Run(() => Main.StartProcess(ShellCommand.RunAsDifferentUser, info)); + + return true; + }, + IcoPath = "Images/user.png" + }, new Result { Title = api.GetTranslation("wox_plugin_program_run_as_administrator"), @@ -102,7 +117,7 @@ namespace Wox.Plugin.Program.Programs WorkingDirectory = ParentDirectory, Verb = "runas" }; - var hide = Main.StartProcess(info); + var hide = Main.StartProcess(Process.Start, info); return hide; }, IcoPath = "Images/cmd.png" @@ -112,7 +127,7 @@ namespace Wox.Plugin.Program.Programs Title = api.GetTranslation("wox_plugin_program_open_containing_folder"), Action = _ => { - var hide = Main.StartProcess(new ProcessStartInfo(ParentDirectory)); + var hide = Main.StartProcess(Process.Start, new ProcessStartInfo(ParentDirectory)); return hide; }, IcoPath = "Images/folder.png" diff --git a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj index 850f972ca4..91dada0670 100644 --- a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj +++ b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj @@ -112,6 +112,9 @@ PreserveNewest + + Always + MSBuild:Compile Designer diff --git a/Wox.Plugin/SharedCommands/ShellCommand.cs b/Wox.Plugin/SharedCommands/ShellCommand.cs index d7071e7353..9da535150c 100644 --- a/Wox.Plugin/SharedCommands/ShellCommand.cs +++ b/Wox.Plugin/SharedCommands/ShellCommand.cs @@ -2,14 +2,65 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Wox.Plugin.SharedCommands { public static class ShellCommand { - public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory="", string arguments = "", string verb = "") + public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam); + [DllImport("user32.dll")] static extern bool EnumThreadWindows(uint threadId, EnumThreadDelegate lpfn, IntPtr lParam); + [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount); + [DllImport("user32.dll")] static extern int GetWindowTextLength(IntPtr hwnd); + + private static bool containsSecurityWindow; + + public static Process RunAsDifferentUser(ProcessStartInfo processStartInfo) + { + processStartInfo.Verb = "RunAsUser"; + var process = Process.Start(processStartInfo); + + containsSecurityWindow = false; + while (!containsSecurityWindow) // wait for windows to bring up the "Windows Security" dialog + { + CheckSecurityWindow(); + Thread.Sleep(25); + } + while (containsSecurityWindow) // while this process contains a "Windows Security" dialog, stay open + { + containsSecurityWindow = false; + CheckSecurityWindow(); + Thread.Sleep(50); + } + + return process; + } + + private static void CheckSecurityWindow() + { + ProcessThreadCollection ptc = Process.GetCurrentProcess().Threads; + for (int i = 0; i < ptc.Count; i++) + EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero); + } + + private static bool CheckSecurityThread(IntPtr hwnd, IntPtr lParam) + { + if (GetWindowTitle(hwnd) == "Windows Security") + containsSecurityWindow = true; + return true; + } + + private static string GetWindowTitle(IntPtr hwnd) + { + StringBuilder sb = new StringBuilder(GetWindowTextLength(hwnd) + 1); + GetWindowText(hwnd, sb, sb.Capacity); + return sb.ToString(); + } + + public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "") { var info = new ProcessStartInfo {