public static InputWriterOnlyPseudoConsole Create() { var(inputReader, inputWriter) = FilePal.CreatePipePair(); var outputWriter = FilePal.OpenNullDevice(FileAccess.Write); var hPC = SafePseudoConsoleHandle.Create(inputReader, outputWriter); return(new InputWriterOnlyPseudoConsole(hPC, inputWriter)); }
private SafeFileHandle OpenNullDevice(FileAccess access) { EnsureObjectsToDispose(); var handle = FilePal.OpenNullDevice(access); _objectsToDispose.Add(handle); return(handle); }
private SafeFileHandle ChooseOutput( OutputRedirection redirection, string fileName, SafeFileHandle handle, SafeFileHandle outputPipe, SafeFileHandle errorPipe) { switch (redirection) { case OutputRedirection.ParentOutput: return(ConsolePal.GetStdOutputHandleForChild() ?? OpenNullDevice(FileAccess.Write)); case OutputRedirection.ParentError: return(ConsolePal.GetStdErrorHandleForChild() ?? OpenNullDevice(FileAccess.Write)); case OutputRedirection.OutputPipe: return(outputPipe); case OutputRedirection.ErrorPipe: return(errorPipe); case OutputRedirection.File: return(OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)); case OutputRedirection.AppendToFile: return(OpenFile(fileName, FileMode.Append, FileAccess.Write, FileShare.Read)); case OutputRedirection.Handle: return(handle); case OutputRedirection.NullDevice: return(FilePal.OpenNullDevice(FileAccess.Write)); default: throw new ArgumentOutOfRangeException(nameof(redirection), "Not a valid value for " + nameof(OutputRedirection) + "."); } }
public SafeFileHandle GetStdErrorHandleForChild(bool createNewConsole) => DuplicateStdFileForChild(StdErrFileNo, createNewConsole) ?? FilePal.OpenNullDevice(System.IO.FileAccess.Write);
public SafeFileHandle GetStdInputHandleForChild(bool createNewConsole) => DuplicateStdFileForChild(StdInFileNo, createNewConsole) ?? FilePal.OpenNullDevice(System.IO.FileAccess.Read);
public SafeFileHandle GetStdErrorHandleForChild(bool createNewConsole) => GetStdHandleForChild(Kernel32.STD_ERROR_HANDLE, createNewConsole) ?? FilePal.OpenNullDevice(System.IO.FileAccess.Write);
public SafeFileHandle GetStdInputHandleForChild(bool createNewConsole) => GetStdHandleForChild(Kernel32.STD_INPUT_HANDLE, createNewConsole) ?? FilePal.OpenNullDevice(System.IO.FileAccess.Read);
public PipelineStdHandleCreator(ref ChildProcessStartInfoInternal startInfo) { var stdInputRedirection = startInfo.StdInputRedirection; var stdOutputRedirection = startInfo.StdOutputRedirection; var stdErrorRedirection = startInfo.StdErrorRedirection; var stdInputFile = startInfo.StdInputFile; var stdOutputFile = startInfo.StdOutputFile; var stdErrorFile = startInfo.StdErrorFile; var stdInputHandle = startInfo.StdInputHandle; var stdOutputHandle = startInfo.StdOutputHandle; var stdErrorHandle = startInfo.StdErrorHandle; if (stdInputRedirection == InputRedirection.Handle && stdInputHandle == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdInputHandle)} must not be null.", nameof(startInfo)); } if (stdInputRedirection == InputRedirection.File && stdInputFile == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdInputFile)} must not be null.", nameof(startInfo)); } if (stdOutputRedirection == OutputRedirection.Handle && stdOutputHandle == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdOutputHandle)} must not be null.", nameof(startInfo)); } if (IsFileRedirection(stdOutputRedirection) && stdOutputFile == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdOutputFile)} must not be null.", nameof(startInfo)); } if (stdErrorRedirection == OutputRedirection.Handle && stdErrorHandle == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdErrorHandle)} must not be null.", nameof(startInfo)); } if (IsFileRedirection(stdErrorRedirection) && stdErrorFile == null) { throw new ArgumentException($"{nameof(ChildProcessStartInfo.StdErrorFile)} must not be null.", nameof(startInfo)); } bool redirectingToSameFile = IsFileRedirection(stdOutputRedirection) && IsFileRedirection(stdErrorRedirection) && stdOutputFile == stdErrorFile; if (redirectingToSameFile && stdErrorRedirection != stdOutputRedirection) { throw new ArgumentException( "StdOutputRedirection and StdErrorRedirection must be the same value when both stdout and stderr redirect to the same file.", nameof(startInfo)); } try { if (stdInputRedirection == InputRedirection.InputPipe) { (InputStream, _inputReadPipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.Out); } if (stdOutputRedirection == OutputRedirection.OutputPipe || stdErrorRedirection == OutputRedirection.OutputPipe) { (OutputStream, _outputWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In); } if (stdOutputRedirection == OutputRedirection.ErrorPipe || stdErrorRedirection == OutputRedirection.ErrorPipe) { (ErrorStream, _errorWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In); } PipelineStdIn = ChooseInput( stdInputRedirection, stdInputFile, stdInputHandle, _inputReadPipe, startInfo.CreateNewConsole); PipelineStdOut = ChooseOutput( stdOutputRedirection, stdOutputFile, stdOutputHandle, _outputWritePipe, _errorWritePipe, startInfo.CreateNewConsole); if (redirectingToSameFile) { PipelineStdErr = PipelineStdOut; } else { PipelineStdErr = ChooseOutput( stdErrorRedirection, stdErrorFile, stdErrorHandle, _outputWritePipe, _errorWritePipe, startInfo.CreateNewConsole); } } catch { Dispose(); throw; } }
public PipelineStdHandleCreator( InputRedirection stdInputRedirection, OutputRedirection stdOutputRedirection, OutputRedirection stdErrorRedirection, string stdInputFile, string stdOutputFile, string stdErrorFile, SafeFileHandle stdInputHandle, SafeFileHandle stdOutputHandle, SafeFileHandle stdErrorHandle) { if (stdInputRedirection == InputRedirection.Handle && stdInputHandle == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdInputHandle)); } if (stdInputRedirection == InputRedirection.File && stdInputFile == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdInputFile)); } if (stdOutputRedirection == OutputRedirection.Handle && stdOutputHandle == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdOutputHandle)); } if (IsFileRedirection(stdOutputRedirection) && stdOutputFile == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdOutputFile)); } if (stdErrorRedirection == OutputRedirection.Handle && stdErrorHandle == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdErrorHandle)); } if (IsFileRedirection(stdErrorRedirection) && stdErrorFile == null) { throw new ArgumentNullException(nameof(ChildProcessStartInfo.StdErrorFile)); } bool redirectingToSameFile = IsFileRedirection(stdOutputRedirection) && IsFileRedirection(stdErrorRedirection) && stdOutputFile == stdErrorFile; if (redirectingToSameFile && stdErrorRedirection != stdOutputRedirection) { throw new ArgumentException( "StdOutputRedirection and StdErrorRedirection must be the same value when both stdout and stderr redirect to the same file.", nameof(ChildProcessStartInfo.StdErrorRedirection)); } try { if (stdInputRedirection == InputRedirection.InputPipe) { (this.InputStream, _inputReadPipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.Out); } if (stdOutputRedirection == OutputRedirection.OutputPipe || stdErrorRedirection == OutputRedirection.OutputPipe) { (this.OutputStream, _outputWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In); } if (stdOutputRedirection == OutputRedirection.ErrorPipe || stdErrorRedirection == OutputRedirection.ErrorPipe) { (this.ErrorStream, _errorWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In); } this.PipelineStdIn = ChooseInput( stdInputRedirection, stdInputFile, stdInputHandle, _inputReadPipe); this.PipelineStdOut = ChooseOutput( stdOutputRedirection, stdOutputFile, stdOutputHandle, _outputWritePipe, _errorWritePipe); if (redirectingToSameFile) { this.PipelineStdErr = this.PipelineStdOut; } else { this.PipelineStdErr = ChooseOutput( stdErrorRedirection, stdErrorFile, stdErrorHandle, _outputWritePipe, _errorWritePipe); } } catch { Dispose(); throw; } }
// 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(); } }