Files

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;
}
}
}