130 lines
4.4 KiB
C#
130 lines
4.4 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
|
|
class A
|
|
{
|
|
private const int STD_OUTPUT_HANDLE = -11;
|
|
private const int STD_ERROR_HANDLE = -12;
|
|
|
|
private const uint CREATE_SUSPENDED = 0x00000004;
|
|
private const uint DETACHED_PROCESS = 0x00000008;
|
|
|
|
private const int STARTF_USESTDHANDLES = 0x00000100;
|
|
private static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
|
|
|
|
private const uint WINSTA_ALL_ACCESS = 0x37F;
|
|
|
|
[DllImport("kernel32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool CreateProcess(
|
|
string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes,
|
|
IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
|
|
string lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo,
|
|
out PROCESS_INFORMATION lpProcessInformation);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool GetExitCodeProcess(IntPtr hProcess, out int lpExitCode);
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
struct STARTUPINFO
|
|
{
|
|
public Int32 cb;
|
|
public string lpReserved;
|
|
public string lpDesktop;
|
|
public string lpTitle;
|
|
public Int32 dwX;
|
|
public Int32 dwY;
|
|
public Int32 dwXSize;
|
|
public Int32 dwYSize;
|
|
public Int32 dwXCountChars;
|
|
public Int32 dwYCountChars;
|
|
public Int32 dwFillAttribute;
|
|
public Int32 dwFlags;
|
|
public Int16 wShowWindow;
|
|
public Int16 cbReserved2;
|
|
public IntPtr lpReserved2;
|
|
public IntPtr hStdInput;
|
|
public IntPtr hStdOutput;
|
|
public IntPtr hStdError;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal struct PROCESS_INFORMATION
|
|
{
|
|
public IntPtr hProcess;
|
|
public IntPtr hThread;
|
|
public int dwProcessId;
|
|
public int dwThreadId;
|
|
}
|
|
|
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
private static extern IntPtr CreateWindowStation(string lpwinsta, uint dwReserved, uint dwDesiredAccess, IntPtr lpsa);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern bool SetProcessWindowStation(IntPtr hWinSta);
|
|
|
|
public static int Main(string[] args)
|
|
{
|
|
// The main executable is in the parent directory and named the same
|
|
string execPath = Assembly.GetExecutingAssembly().Location;
|
|
string fileName = Path.GetFileName(execPath);
|
|
string mainExecutablePath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(execPath)), fileName);
|
|
Console.WriteLine(mainExecutablePath);
|
|
|
|
// Propagate the command line
|
|
StringBuilder argsSub = new StringBuilder();
|
|
argsSub.Append('"').Append(mainExecutablePath).Append('"').Append(' ');
|
|
for (int i = 0; i < args.Length; i++)
|
|
argsSub.Append('"').Append(args[i]).Append('"').Append(' ');
|
|
|
|
// Propagate environment variables
|
|
StringBuilder env = new StringBuilder();
|
|
foreach (DictionaryEntry i in Environment.GetEnvironmentVariables())
|
|
env.Append((string)i.Key).Append('=').Append((string)i.Value).Append('\0');
|
|
|
|
// Use a new window-station so that Environment.UserInteractive becomes false
|
|
// search for WSF_VISIBLE
|
|
// or see https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/SystemInformation.cs,416f4f3dac9f38f1,references
|
|
IntPtr hSta = CreateWindowStation("detach", 0, WINSTA_ALL_ACCESS, IntPtr.Zero);
|
|
if (!SetProcessWindowStation(hSta)) {
|
|
Console.Error.WriteLine("Failed to switch to a new windows station.");
|
|
return 10;
|
|
}
|
|
|
|
STARTUPINFO si = new STARTUPINFO();
|
|
si.cb = Marshal.SizeOf(si);
|
|
si.hStdInput = INVALID_HANDLE_VALUE;
|
|
si.hStdOutput = INVALID_HANDLE_VALUE;
|
|
si.hStdError = INVALID_HANDLE_VALUE;
|
|
si.dwFlags = 0;
|
|
|
|
// Start the process detached from the current console and thus losing
|
|
// the "interactiveness"
|
|
PROCESS_INFORMATION pi;
|
|
if (!CreateProcess(mainExecutablePath, argsSub.ToString(), IntPtr.Zero, IntPtr.Zero, false, 0, env.ToString(), null, ref si, out pi))
|
|
{
|
|
Console.Error.WriteLine(string.Format("Failed to start process '{0}'.", mainExecutablePath));
|
|
return 2;
|
|
}
|
|
|
|
using (Process p = Process.GetProcessById(pi.dwProcessId))
|
|
{
|
|
p.WaitForExit();
|
|
|
|
int exitCode;
|
|
if (!GetExitCodeProcess(pi.hProcess, out exitCode))
|
|
{
|
|
Console.Error.WriteLine("Failed to get the exit code.");
|
|
return 3;
|
|
}
|
|
return exitCode;
|
|
}
|
|
}
|
|
}
|