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