public unsafe IChildProcessStateHolder SpawnProcess( ref ChildProcessStartInfoInternal startInfo, string resolvedPath, SafeHandle stdIn, SafeHandle stdOut, SafeHandle stdErr) { var arguments = startInfo.Arguments; var environmentVariables = startInfo.EnvironmentVariables; var workingDirectory = startInfo.WorkingDirectory; var flags = startInfo.Flags; Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow()); var commandLine = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting()); var environmentBlock = environmentVariables != null?WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables) : null; var pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null; try { if (pseudoConsole is { } && flags.HasUseCustomCodePage()) { ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory); } using var inheritableHandleStore = new InheritableHandleStore(3); var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null; var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null; var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null; Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(2); if (pseudoConsole is { })
public unsafe IChildProcessStateHolder SpawnProcess( ref ChildProcessStartInfoInternal startInfo, string resolvedPath, SafeHandle stdIn, SafeHandle stdOut, SafeHandle stdErr) { var arguments = startInfo.Arguments; var environmentVariables = startInfo.EnvironmentVariables; var workingDirectory = startInfo.WorkingDirectory; var flags = startInfo.Flags; Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow()); var commandLine = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting()); var environmentBlock = startInfo.UseCustomEnvironmentVariables ? WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables.Span) : null; // Objects that need cleanup InputWriterOnlyPseudoConsole?pseudoConsole = null; SafeJobObjectHandle? jobObjectHandle = null; SafeProcessHandle? processHandle = null; SafeThreadHandle? threadHandle = null; try { pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null; if (pseudoConsole is not null && flags.HasUseCustomCodePage()) { ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory); } bool killOnClose = startInfo.AllowSignal && WindowsVersion.NeedsWorkaroundForWindows1809; jobObjectHandle = CreateJobObject(killOnClose, startInfo.DisableWindowsErrorReportingDialog); using var inheritableHandleStore = new InheritableHandleStore(3); var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null; var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null; var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null; IntPtr jobObjectHandles = jobObjectHandle.DangerousGetHandle(); Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(3); if (pseudoConsole is not null) { attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle()); } attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length); attr.UpdateJobList(&jobObjectHandles, 1); const int CreationFlags = Kernel32.CREATE_UNICODE_ENVIRONMENT | Kernel32.EXTENDED_STARTUPINFO_PRESENT; int processId; (processId, processHandle, threadHandle) = InvokeCreateProcess( commandLine, CreationFlags, environmentBlock, workingDirectory, childStdIn, childStdOut, childStdErr, attr); return(new WindowsChildProcessState(processId, processHandle, jobObjectHandle, pseudoConsole, startInfo.AllowSignal)); } } catch { if (processHandle is not null) { Kernel32.TerminateProcess(processHandle, -1); processHandle.Dispose(); } pseudoConsole?.Dispose(); jobObjectHandle?.Dispose(); throw; } finally { threadHandle?.Dispose(); } }
// Change the code page of the specified pseudo console by invoking chcp.com on it. private static unsafe void ChangeCodePage( InputWriterOnlyPseudoConsole pseudoConsole, int codePage, string?workingDirectory) { var commandLine = new StringBuilder(ChcpPath.Length + 5); WindowsCommandLineUtil.AppendStringQuoted(commandLine, ChcpPath); commandLine.Append(' '); commandLine.Append(codePage.ToString(CultureInfo.InvariantCulture)); using var inheritableHandleStore = new InheritableHandleStore(3); using var nullDevice = FilePal.OpenNullDevice(FileAccess.ReadWrite); var childStdIn = inheritableHandleStore.Add(nullDevice); var childStdOut = inheritableHandleStore.Add(nullDevice); var childStdErr = inheritableHandleStore.Add(nullDevice); SafeProcessHandle?processHandle = null; try { Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(2); attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle()); attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length); const int CreationFlags = Kernel32.CREATE_UNICODE_ENVIRONMENT | Kernel32.EXTENDED_STARTUPINFO_PRESENT; SafeThreadHandle threadHandle; (_, processHandle, threadHandle) = InvokeCreateProcess( commandLine, CreationFlags, null, workingDirectory, childStdIn, childStdOut, childStdErr, attr); threadHandle.Dispose(); } using var waitHandle = new WindowsProcessWaitHandle(processHandle); waitHandle.WaitOne(); if (!Kernel32.GetExitCodeProcess(processHandle, out var exitCode)) { throw new Win32Exception(); } if (exitCode != 0) { ThrowHelper.ThrowChcpFailedException(codePage, exitCode, nameof(codePage)); } } finally { processHandle?.Dispose(); } }