diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index af53c79a5..a6ca023be 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -198,9 +198,9 @@ namespace Artemis.Core.Services
// ReSharper disable InconsistentlySynchronizedField - It's read-only, idc
_logger.Debug("Loaded {count} plugin(s)", _plugins.Count);
-
- bool mustElevate = !isElevated && _plugins.Any(p => p.Entity.IsEnabled && p.Info.RequiresAdmin);
- if (mustElevate)
+
+ bool adminRequired = _plugins.Any(p => p.Entity.IsEnabled && p.Info.RequiresAdmin);
+ if (!isElevated && adminRequired)
{
_logger.Information("Restarting because one or more plugins requires elevation");
// No need for a delay this early on, nothing that needs graceful shutdown is happening yet
@@ -208,6 +208,13 @@ namespace Artemis.Core.Services
return;
}
+ if (isElevated && !adminRequired)
+ {
+ // No need for a delay this early on, nothing that needs graceful shutdown is happening yet
+ Utilities.Restart(false, TimeSpan.Zero);
+ return;
+ }
+
foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled))
EnablePlugin(plugin, false, ignorePluginLock);
diff --git a/src/Artemis.Core/Utilities/Utilities.cs b/src/Artemis.Core/Utilities/Utilities.cs
index 47861c970..fa03f516d 100644
--- a/src/Artemis.Core/Utilities/Utilities.cs
+++ b/src/Artemis.Core/Utilities/Utilities.cs
@@ -1,7 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
-using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
@@ -35,7 +34,7 @@ namespace Artemis.Core
}
///
- /// Restarts the application
+ /// Restarts the application
///
/// Whether the application should be restarted with elevated permissions
/// Delay in seconds before killing process and restarting
@@ -90,6 +89,11 @@ namespace Artemis.Core
}
}
+ private static void OnRestartRequested(RestartEventArgs e)
+ {
+ RestartRequested?.Invoke(null, e);
+ }
+
#region Events
///
@@ -98,20 +102,15 @@ namespace Artemis.Core
public static event EventHandler? ShutdownRequested;
///
- /// Occurs when the core has requested an application restart
+ /// Occurs when the core has requested an application restart
///
public static event EventHandler? RestartRequested;
-
+
private static void OnShutdownRequested()
{
ShutdownRequested?.Invoke(null, EventArgs.Empty);
}
#endregion
-
- private static void OnRestartRequested(RestartEventArgs e)
- {
- RestartRequested?.Invoke(null, e);
- }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index db296971a..d185a83fb 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -40,7 +40,7 @@
-
+
false
@@ -318,11 +318,20 @@
True
Resources.resx
+
+ True
+ True
+ Settings.settings
+
PreserveNewest
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs
index 400ded1a6..2a0bf0f65 100644
--- a/src/Artemis.UI/Bootstrapper.cs
+++ b/src/Artemis.UI/Bootstrapper.cs
@@ -17,6 +17,7 @@ using Artemis.UI.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Stylet;
+using Artemis.UI.Utilities;
using Ninject;
using Serilog;
using SharpVectors.Dom.Resources;
@@ -70,16 +71,10 @@ namespace Artemis.UI
});
// Initialize the core async so the UI can show the progress
- Task.Run(async () =>
+ Task.Run(() =>
{
try
{
- if (StartupArguments.Contains("--autorun"))
- {
- logger.Information("Sleeping for 15 seconds on auto run to allow vendor applications required for SDKs to start");
- await Task.Delay(TimeSpan.FromSeconds(15));
- }
-
_core.StartupArguments = StartupArguments;
_core.IsElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
_core.Initialize();
@@ -144,15 +139,25 @@ namespace Artemis.UI
private void UtilitiesOnRestartRequested(object sender, RestartEventArgs e)
{
- ProcessStartInfo info = new()
+ string args = Args.Any() ? "-ArgumentList " + string.Join(',', Args.Select(a => "'" + a + "'")) : "";
+
+ if (e.Elevate)
{
- Arguments =
- $"-Command \"& {{Start-Sleep -Milliseconds {(int) e.Delay.TotalMilliseconds}; (Get-Process 'Artemis.UI').kill(); Start-Process -FilePath '{Constants.ExecutablePath}' {(e.Elevate ? "-Verb RunAs" : "")}}}\"",
- WindowStyle = ProcessWindowStyle.Hidden,
- CreateNoWindow = true,
- FileName = "PowerShell.exe"
- };
- Process.Start(info);
+ ProcessStartInfo info = new()
+ {
+ Arguments =
+ $"-Command \"& {{Start-Sleep -Milliseconds {(int) e.Delay.TotalMilliseconds}; (Get-Process 'Artemis.UI').kill(); Start-Process -FilePath '{Constants.ExecutablePath}' {args} -Verb RunAs}}\"",
+ WindowStyle = ProcessWindowStyle.Hidden,
+ CreateNoWindow = true,
+ FileName = "PowerShell.exe"
+ };
+ Process.Start(info);
+ }
+ else
+ {
+ ProcessUtilities.RunAsDesktopUser(Constants.ExecutablePath);
+ }
+
Execute.OnUIThread(() => Application.Current.Shutdown());
}
diff --git a/src/Artemis.UI/Properties/Resources.Designer.cs b/src/Artemis.UI/Properties/Resources.Designer.cs
index a0fb0a67b..38a2162d0 100644
--- a/src/Artemis.UI/Properties/Resources.Designer.cs
+++ b/src/Artemis.UI/Properties/Resources.Designer.cs
@@ -190,6 +190,30 @@ namespace Artemis.UI.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-16"?>
+ ///<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
+ /// <RegistrationInfo>
+ /// <Date>2021-01-24T15:05:33.7954017</Date>
+ /// <Author>DESKTOP-8CH3TD6\Robert</Author>
+ /// <URI>\Artemis 2 - Autorun</URI>
+ /// </RegistrationInfo>
+ /// <Triggers>
+ /// <LogonTrigger>
+ /// <Enabled>true</Enabled>
+ /// <Delay>PT15S</Delay>
+ /// </LogonTrigger>
+ /// </Triggers>
+ /// <Principals>
+ /// <Principal id="Author">
+ /// <UserId>S-1-5-21-184080501-1733858 [rest of string was truncated]";.
+ ///
+ internal static string artemis_autorun {
+ get {
+ return ResourceManager.GetString("artemis-autorun", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
diff --git a/src/Artemis.UI/Properties/Resources.resx b/src/Artemis.UI/Properties/Resources.resx
index 96a38f334..a7f768ddc 100644
--- a/src/Artemis.UI/Properties/Resources.resx
+++ b/src/Artemis.UI/Properties/Resources.resx
@@ -112,12 +112,12 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
..\resources\cursors\aero_crosshair.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
@@ -157,6 +157,9 @@
..\resources\cursors\aero_rotate_tr.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\Artemis 2 - Autorun.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16
+
..\resources\images\logo\bow.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
diff --git a/src/Artemis.UI/Properties/Settings.Designer.cs b/src/Artemis.UI/Properties/Settings.Designer.cs
index 93cac3d15..e1e14bb61 100644
--- a/src/Artemis.UI/Properties/Settings.Designer.cs
+++ b/src/Artemis.UI/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace Artemis.UI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
diff --git a/src/Artemis.UI/Properties/launchSettings.json b/src/Artemis.UI/Properties/launchSettings.json
index a11fc1923..948a8e1bb 100644
--- a/src/Artemis.UI/Properties/launchSettings.json
+++ b/src/Artemis.UI/Properties/launchSettings.json
@@ -1,7 +1,8 @@
{
"profiles": {
"Artemis.UI": {
- "commandName": "Project"
+ "commandName": "Project",
+ "commandLineArgs": "--test --test2"
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Resources/Artemis 2 - Autorun.xml b/src/Artemis.UI/Resources/Artemis 2 - Autorun.xml
new file mode 100644
index 000000000..e31980c8b
Binary files /dev/null and b/src/Artemis.UI/Resources/Artemis 2 - Autorun.xml differ
diff --git a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs
index 86109e851..e4d884880 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs
@@ -8,12 +8,16 @@ namespace Artemis.UI.Screens.Settings.Debug
{
public class DebugViewModel : Conductor.Collection.OneActive
{
+ private readonly ICoreService _coreService;
+
public DebugViewModel(
ISettingsService settingsService,
+ ICoreService coreService,
RenderDebugViewModel renderDebugViewModel,
DataModelDebugViewModel dataModelDebugViewModel,
LogsDebugViewModel logsDebugViewModel)
{
+ _coreService = coreService;
Items.Add(renderDebugViewModel);
Items.Add(dataModelDebugViewModel);
Items.Add(logsDebugViewModel);
@@ -51,7 +55,7 @@ namespace Artemis.UI.Screens.Settings.Debug
public void Restart()
{
- Core.Utilities.Restart(false, TimeSpan.FromMilliseconds(500));
+ Core.Utilities.Restart(_coreService.IsElevated, TimeSpan.FromMilliseconds(500));
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
index 8615fd8fc..3a41acea1 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
@@ -3,10 +3,15 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Net.Mime;
using System.Threading.Tasks;
+using System.Windows;
+using System.Xml.Linq;
+using System.Xml.XPath;
using Artemis.Core;
using Artemis.Core.LayerBrushes;
using Artemis.Core.Services;
+using Artemis.UI.Properties;
using Artemis.UI.Screens.StartupWizard;
using Artemis.UI.Services;
using Artemis.UI.Services.Interfaces;
@@ -290,24 +295,103 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
private void ApplyAutorun()
{
+ if (!StartWithWindows)
+ StartMinimized = false;
+
+ // Remove the old auto-run method of placing a shortcut in shell:startup
+ string autoRunFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Artemis.lnk");
+ if (File.Exists(autoRunFile))
+ File.Delete(autoRunFile);
+
+ // Create or remove the task if necessary
try
{
- string autoRunFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Artemis.lnk");
- string executableFile = Constants.ExecutablePath;
+ Process schtasks = new()
+ {
+ StartInfo =
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = true,
+ FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
+ Arguments = "/TN \"Artemis 2 autorun\""
+ }
+ };
- if (File.Exists(autoRunFile))
- File.Delete(autoRunFile);
- if (StartWithWindows)
- ShortcutUtilities.Create(autoRunFile, executableFile, "--autorun", new FileInfo(executableFile).DirectoryName, "Artemis", "", "");
- else
- StartMinimized = false;
+ schtasks.Start();
+ schtasks.WaitForExit();
+ bool taskCreated = schtasks.ExitCode == 0;
+
+ if (StartWithWindows && !taskCreated)
+ CreateAutoRunTask();
+ else if (!StartWithWindows && taskCreated)
+ RemoveAutoRunTask();
}
catch (Exception e)
{
- _dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e);
+ Execute.PostToUIThread(() => _dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e));
throw;
}
}
+
+ private void CreateAutoRunTask()
+ {
+ XDocument document = XDocument.Parse(Resources.artemis_autorun);
+ XElement task = document.Descendants().First();
+
+ task.Descendants().First(d => d.Name.LocalName == "RegistrationInfo").Descendants().First(d => d.Name.LocalName == "Date")
+ .SetValue(DateTime.Now);
+ task.Descendants().First(d => d.Name.LocalName == "RegistrationInfo").Descendants().First(d => d.Name.LocalName == "Author")
+ .SetValue(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
+
+ task.Descendants().First(d => d.Name.LocalName == "Principals").Descendants().First(d => d.Name.LocalName == "Principal").Descendants().First(d => d.Name.LocalName == "UserId")
+ .SetValue(System.Security.Principal.WindowsIdentity.GetCurrent().User.Value);
+
+ task.Descendants().First(d => d.Name.LocalName == "Actions").Descendants().First(d => d.Name.LocalName == "Exec").Descendants().First(d => d.Name.LocalName == "WorkingDirectory")
+ .SetValue(Constants.ApplicationFolder);
+ task.Descendants().First(d => d.Name.LocalName == "Actions").Descendants().First(d => d.Name.LocalName == "Exec").Descendants().First(d => d.Name.LocalName == "Command")
+ .SetValue("\"" + Constants.ExecutablePath + "\"");
+
+ string xmlPath = Path.GetTempFileName();
+ using (Stream fileStream = new FileStream(xmlPath, FileMode.Create))
+ {
+ document.Save(fileStream);
+ }
+
+ Process schtasks = new()
+ {
+ StartInfo =
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = true,
+ Verb = "runas",
+ FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
+ Arguments = $"/Create /XML \"{xmlPath}\" /tn \"Artemis 2 autorun\""
+ }
+ };
+
+ schtasks.Start();
+ schtasks.WaitForExit();
+
+ File.Delete(xmlPath);
+ }
+
+ private void RemoveAutoRunTask()
+ {
+ Process schtasks = new()
+ {
+ StartInfo =
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = true,
+ Verb = "runas",
+ FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
+ Arguments = "/Delete /TN \"Artemis 2 autorun\" /f"
+ }
+ };
+
+ schtasks.Start();
+ schtasks.WaitForExit();
+ }
}
public enum ApplicationColorScheme
diff --git a/src/Artemis.UI/Utilities/ProcessUtilities.cs b/src/Artemis.UI/Utilities/ProcessUtilities.cs
new file mode 100644
index 000000000..18c251774
--- /dev/null
+++ b/src/Artemis.UI/Utilities/ProcessUtilities.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Artemis.UI.Utilities
+{
+ public static class ProcessUtilities
+ {
+ public static Task RunProcessAsync(string fileName, string arguments)
+ {
+ TaskCompletionSource tcs = new();
+
+ Process process = new()
+ {
+ StartInfo = {FileName = fileName, Arguments = arguments},
+ EnableRaisingEvents = true
+ };
+
+ process.Exited += (sender, args) =>
+ {
+ tcs.SetResult(process.ExitCode);
+ process.Dispose();
+ };
+
+ process.Start();
+
+ return tcs.Task;
+ }
+
+ public static void RunAsDesktopUser(string fileName)
+ {
+ if (string.IsNullOrWhiteSpace(fileName))
+ throw new ArgumentException("Value cannot be null or whitespace.", nameof(fileName));
+
+ // To start process as shell user you will need to carry out these steps:
+ // 1. Enable the SeIncreaseQuotaPrivilege in your current token
+ // 2. Get an HWND representing the desktop shell (GetShellWindow)
+ // 3. Get the Process ID(PID) of the process associated with that window(GetWindowThreadProcessId)
+ // 4. Open that process(OpenProcess)
+ // 5. Get the access token from that process (OpenProcessToken)
+ // 6. Make a primary token with that token(DuplicateTokenEx)
+ // 7. Start the new process with that primary token(CreateProcessWithTokenW)
+
+ IntPtr hProcessToken = IntPtr.Zero;
+ // Enable SeIncreaseQuotaPrivilege in this process. (This won't work if current process is not elevated.)
+ try
+ {
+ IntPtr process = GetCurrentProcess();
+ if (!OpenProcessToken(process, 0x0020, ref hProcessToken))
+ return;
+
+ TOKEN_PRIVILEGES tkp = new()
+ {
+ PrivilegeCount = 1,
+ Privileges = new LUID_AND_ATTRIBUTES[1]
+ };
+
+ if (!LookupPrivilegeValue(null, "SeIncreaseQuotaPrivilege", ref tkp.Privileges[0].Luid))
+ return;
+
+ tkp.Privileges[0].Attributes = 0x00000002;
+
+ if (!AdjustTokenPrivileges(hProcessToken, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero))
+ return;
+ }
+ finally
+ {
+ CloseHandle(hProcessToken);
+ }
+
+ // Get an HWND representing the desktop shell.
+ // CAVEATS: This will fail if the shell is not running (crashed or terminated), or the default shell has been
+ // replaced with a custom shell. This also won't return what you probably want if Explorer has been terminated and
+ // restarted elevated.
+ IntPtr hwnd = GetShellWindow();
+ if (hwnd == IntPtr.Zero)
+ return;
+
+ IntPtr hShellProcess = IntPtr.Zero;
+ IntPtr hShellProcessToken = IntPtr.Zero;
+ IntPtr hPrimaryToken = IntPtr.Zero;
+ try
+ {
+ // Get the PID of the desktop shell process.
+ uint dwPID;
+ if (GetWindowThreadProcessId(hwnd, out dwPID) == 0)
+ return;
+
+ // Open the desktop shell process in order to query it (get the token)
+ hShellProcess = OpenProcess(ProcessAccessFlags.QueryInformation, false, dwPID);
+ if (hShellProcess == IntPtr.Zero)
+ return;
+
+ // Get the process token of the desktop shell.
+ if (!OpenProcessToken(hShellProcess, 0x0002, ref hShellProcessToken))
+ return;
+
+ uint dwTokenRights = 395U;
+
+ // Duplicate the shell's process token to get a primary token.
+ // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
+ if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out hPrimaryToken))
+ return;
+
+ // Start the target process with the new token.
+ STARTUPINFO si = new();
+ PROCESS_INFORMATION pi = new();
+ if (!CreateProcessWithTokenW(hPrimaryToken, 0, fileName, "", 0, IntPtr.Zero, Path.GetDirectoryName(fileName), ref si, out pi))
+ return;
+ }
+ finally
+ {
+ CloseHandle(hShellProcessToken);
+ CloseHandle(hPrimaryToken);
+ CloseHandle(hShellProcess);
+ }
+ }
+
+ #region Interop
+
+ private struct TOKEN_PRIVILEGES
+ {
+ public uint PrivilegeCount;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ public LUID_AND_ATTRIBUTES[] Privileges;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ private struct LUID_AND_ATTRIBUTES
+ {
+ public LUID Luid;
+ public uint Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct LUID
+ {
+ public readonly uint LowPart;
+ public readonly int HighPart;
+ }
+
+ [Flags]
+ private enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ private enum SECURITY_IMPERSONATION_LEVEL
+ {
+ SecurityAnonymous,
+ SecurityIdentification,
+ SecurityImpersonation,
+ SecurityDelegation
+ }
+
+ private enum TOKEN_TYPE
+ {
+ TokenPrimary = 1,
+ TokenImpersonation
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct PROCESS_INFORMATION
+ {
+ public readonly IntPtr hProcess;
+ public readonly IntPtr hThread;
+ public readonly int dwProcessId;
+ public readonly int dwThreadId;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct STARTUPINFO
+ {
+ public readonly int cb;
+ public readonly string lpReserved;
+ public readonly string lpDesktop;
+ public readonly string lpTitle;
+ public readonly int dwX;
+ public readonly int dwY;
+ public readonly int dwXSize;
+ public readonly int dwYSize;
+ public readonly int dwXCountChars;
+ public readonly int dwYCountChars;
+ public readonly int dwFillAttribute;
+ public readonly int dwFlags;
+ public readonly short wShowWindow;
+ public readonly short cbReserved2;
+ public readonly IntPtr lpReserved2;
+ public readonly IntPtr hStdInput;
+ public readonly IntPtr hStdOutput;
+ public readonly IntPtr hStdError;
+ }
+
+ [DllImport("kernel32.dll", ExactSpelling = true)]
+ private static extern IntPtr GetCurrentProcess();
+
+ [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
+ private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ private static extern bool LookupPrivilegeValue(string host, string name, ref LUID pluid);
+
+ [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
+ private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TOKEN_PRIVILEGES newst, int len, IntPtr prev, IntPtr relen);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr GetShellWindow();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, uint processId);
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, IntPtr lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL impersonationLevel, TOKEN_TYPE tokenType,
+ out IntPtr phNewToken);
+
+ [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern bool CreateProcessWithTokenW(IntPtr hToken, int dwLogonFlags, string lpApplicationName, string lpCommandLine, int dwCreationFlags, IntPtr lpEnvironment,
+ string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
+
+ #endregion
+ }
+}
\ No newline at end of file