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
{