public ChildProcessStartInfoInternal(ChildProcessStartInfo startInfo) { var flags = startInfo.Flags; FileName = startInfo.FileName; Arguments = startInfo.Arguments; WorkingDirectory = startInfo.WorkingDirectory; Flags = flags; CodePage = startInfo.CodePage; SearchPath = startInfo.SearchPath; StdInputRedirection = startInfo.StdInputRedirection; StdOutputRedirection = startInfo.StdOutputRedirection; StdErrorRedirection = startInfo.StdErrorRedirection; StdInputFile = startInfo.StdInputFile; StdOutputFile = startInfo.StdOutputFile; StdErrorFile = startInfo.StdErrorFile; StdInputHandle = startInfo.StdInputHandle; StdOutputHandle = startInfo.StdOutputHandle; StdErrorHandle = startInfo.StdErrorHandle; if (!flags.HasDisableEnvironmentVariableInheritance() && startInfo.CreationContext is null && startInfo.ExtraEnvironmentVariables.Count == 0) { UseCustomEnvironmentVariables = false; EnvironmentVariables = default; }
public static string ExecuteForStandardOutput(ChildProcessStartInfo si, Encoding?encoding = null) { using var p = ChildProcess.Start(si); if (p.HasStandardInput) { p.StandardInput.Close(); } if (p.HasStandardError) { p.StandardError.Close(); } using var sr = new StreamReader(p.StandardOutput, encoding ?? Encoding.UTF8); var standardOutput = sr.ReadToEnd(); p.WaitForExit(); if (p.ExitCode != 0) { throw new ChildProcessFailedException($"Child process failed with exit code {p.ExitCode} (0x{p.ExitCode:X8})."); } return(standardOutput); }
public void RedirectionToNull() { { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoBack") { StdInputRedirection = InputRedirection.NullDevice, StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.NullDevice, }; using var sut = ChildProcess.Start(si); sut.WaitForExit(); Assert.Equal(0, sut.ExitCode); } { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoOutAndError") { StdInputRedirection = InputRedirection.NullDevice, StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.NullDevice, }; using var sut = ChildProcess.Start(si); sut.WaitForExit(); Assert.Equal(0, sut.ExitCode); } }
public void ConnectsInputPipe() { using var tmp = new TemporaryDirectory(); var outFile = Path.Combine(tmp.Location, "out"); var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoBack") { StdInputRedirection = InputRedirection.InputPipe, StdOutputRedirection = OutputRedirection.File, StdOutputFile = outFile, StdErrorRedirection = OutputRedirection.NullDevice, }; using var sut = ChildProcess.Start(si); const string Text = "foo"; using (var sw = new StreamWriter(sut.StandardInput)) { sw.Write(Text); } sut.WaitForExit(); Assert.True(sut.HasStandardInput); Assert.False(sut.HasStandardOutput); Assert.False(sut.HasStandardError); Assert.Equal(Text, File.ReadAllText(outFile)); }
public void CanSendSignal() { var si = new ChildProcessStartInfo(TestUtil.TestChildNativePath, "ReportSignal") { StdInputRedirection = InputRedirection.InputPipe, StdOutputRedirection = OutputRedirection.OutputPipe, }; using var sut = ChildProcess.Start(si); Assert.True(sut.CanSignal); Assert.Equal('R', sut.StandardOutput.ReadByte()); sut.SignalInterrupt(); Assert.Equal('I', sut.StandardOutput.ReadByte()); sut.SignalInterrupt(); Assert.Equal('I', sut.StandardOutput.ReadByte()); if (!HasWorkaroundForWindows1809) { // NOTE: On Windows, a console app cannot cancel CTRL_CLOSE_EVENT (generated when the attached pseudo console is closed). // It will be killed after the 5s-timeout elapses. Once we call SignalTermination, we must treat the app as already terminated. // https://docs.microsoft.com/en-us/windows/console/handlerroutine#timeouts sut.SignalTermination(); Assert.Equal('T', sut.StandardOutput.ReadByte()); } sut.Kill(); sut.WaitForExit(); Assert.NotEqual(0, sut.ExitCode); }
public void CanObtainExitCode() { { var si = new ChildProcessStartInfo( TestUtil.DotnetCommandName, TestUtil.TestChildPath, "ExitCode", "0"); using var sut = ChildProcess.Start(si); sut.WaitForExit(); Assert.Equal(0, sut.ExitCode); } { // An exit code is 32-bit on Windows while it is 8-bit on POSIX. int nonZeroExitCode = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? unchecked ((int)0xc0000005) : 255; var si = new ChildProcessStartInfo( TestUtil.DotnetCommandName, TestUtil.TestChildPath, "ExitCode", nonZeroExitCode.ToString(CultureInfo.InvariantCulture)); using var sut = ChildProcess.Start(si); sut.WaitForExit(); Assert.NotEqual(0, sut.ExitCode); Assert.Equal(nonZeroExitCode, sut.ExitCode); } }
private static ChildProcessImpl CreateForWaitForExitTest() { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoBack") { StdInputRedirection = InputRedirection.InputPipe, StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.NullDevice, }; return((ChildProcessImpl)ChildProcess.Start(si)); }
public void ChildProcessWaitForAsyncIsTrulyAsynchronous() { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "Sleep", "1000") { StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.NullDevice, }; using var sut = ChildProcess.Start(si); WaitForAsyncIsTrulyAsynchronous(sut); sut.WaitForExit(); Assert.Equal(0, sut.ExitCode); }
static void AssertOne(int codePage) { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoCodePage") { CodePage = codePage, Flags = ChildProcessFlags.UseCustomCodePage, StdOutputRedirection = OutputRedirection.OutputPipe, }; var output = ExecuteForStandardOutput(si); Assert.Equal(codePage.ToString(CultureInfo.InvariantCulture), output); }
/// <summary> /// Starts a child process as specified in <paramref name="startInfo"/>. /// </summary> /// <param name="startInfo"><see cref="ChildProcessStartInfo"/>.</param> /// <returns>The started process.</returns> /// <exception cref="ArgumentException"><paramref name="startInfo"/> has an invalid value.</exception> /// <exception cref="ArgumentNullException"><paramref name="startInfo"/> is null.</exception> /// <exception cref="FileNotFoundException">The executable not found.</exception> /// <exception cref="IOException">Failed to open a specified file.</exception> /// <exception cref="AsmichiChildProcessLibraryCrashedException">The operation failed due to critical disturbance.</exception> /// <exception cref="Win32Exception">Another kind of native errors.</exception> public static IChildProcess Start(ChildProcessStartInfo startInfo) { _ = startInfo ?? throw new ArgumentNullException(nameof(startInfo)); var startInfoInternal = new ChildProcessStartInfoInternal(startInfo); _ = startInfoInternal.FileName ?? throw new ArgumentException("ChildProcessStartInfo.FileName must not be null.", nameof(startInfo)); _ = startInfoInternal.Arguments ?? throw new ArgumentException("ChildProcessStartInfo.Arguments must not be null.", nameof(startInfo)); var flags = startInfoInternal.Flags; if (flags.HasUseCustomCodePage() && flags.HasAttachToCurrentConsole()) { throw new ArgumentException( $"{nameof(ChildProcessFlags.UseCustomCodePage)} cannot be combined with {nameof(ChildProcessFlags.AttachToCurrentConsole)}.", nameof(startInfo)); } var resolvedPath = ResolveExecutablePath(startInfoInternal.FileName, startInfoInternal.Flags); using var stdHandles = new PipelineStdHandleCreator(ref startInfoInternal); IChildProcessStateHolder processState; try { processState = ChildProcessHelper.Shared.SpawnProcess( startInfo: ref startInfoInternal, resolvedPath: resolvedPath, stdIn: stdHandles.PipelineStdIn, stdOut: stdHandles.PipelineStdOut, stdErr: stdHandles.PipelineStdErr); } catch (Win32Exception ex) { if (EnvironmentPal.IsFileNotFoundError(ex.NativeErrorCode)) { ThrowHelper.ThrowExecutableNotFoundException(resolvedPath, startInfoInternal.Flags, ex); } // Win32Exception does not provide detailed information by its type. // The NativeErrorCode and Message property should be enough because normally there is // nothing we can do to programmatically recover from this error. throw; } var process = new ChildProcessImpl(processState, stdHandles.InputStream, stdHandles.OutputStream, stdHandles.ErrorStream); stdHandles.DetachStreams(); return(process); }
public void ExitCodeThrowsBeforeChildExits() { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoBack") { StdInputRedirection = InputRedirection.InputPipe, }; using var sut = ChildProcess.Start(si); Assert.Throws <InvalidOperationException>(() => sut.ExitCode); sut.StandardInput.Close(); sut.WaitForExit(); Assert.Equal(0, sut.ExitCode); }
public void StreamPropertiesThrowWhenNoPipeAssociated() { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "ExitCode", "0") { StdInputRedirection = InputRedirection.NullDevice, StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.NullDevice, }; using var sut = ChildProcess.Start(si); Assert.False(sut.HasStandardInput); Assert.False(sut.HasStandardOutput); Assert.False(sut.HasStandardError); Assert.Throws <InvalidOperationException>(() => sut.StandardInput); Assert.Throws <InvalidOperationException>(() => sut.StandardOutput); Assert.Throws <InvalidOperationException>(() => sut.StandardError); sut.WaitForExit(); }
public void DefaultValueTest() { var sut = new ChildProcessStartInfo(); Assert.Equal(InputRedirection.NullDevice, sut.StdInputRedirection); Assert.Equal(OutputRedirection.ParentOutput, sut.StdOutputRedirection); Assert.Equal(OutputRedirection.ParentError, sut.StdErrorRedirection); Assert.Null(sut.StdInputFile); Assert.Null(sut.StdInputHandle); Assert.Null(sut.StdOutputFile); Assert.Null(sut.StdOutputHandle); Assert.Null(sut.StdErrorFile); Assert.Null(sut.StdErrorHandle); Assert.Null(sut.FileName); Assert.Equal(Array.Empty <string>(), sut.Arguments); Assert.Null(sut.WorkingDirectory); Assert.Equal(Array.Empty <KeyValuePair <string, string> >(), sut.ExtraEnvironmentVariables); Assert.Equal(ChildProcessFlags.None, sut.Flags); Assert.Equal(65001, sut.CodePage); }
public void ConnectsErrorPipe() { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoOutAndError") { StdInputRedirection = InputRedirection.NullDevice, StdOutputRedirection = OutputRedirection.NullDevice, StdErrorRedirection = OutputRedirection.ErrorPipe, }; using var sut = ChildProcess.Start(si); using var sr = new StreamReader(sut.StandardError); var output = sr.ReadToEnd(); sut.WaitForExit(); Assert.False(sut.HasStandardInput); Assert.False(sut.HasStandardOutput); Assert.True(sut.HasStandardError); Assert.Equal(0, sut.ExitCode); Assert.Equal("TestChild.Error", output); }
public void CannotSendSignalIfAttachedToCurrentConsole() { var si = new ChildProcessStartInfo(TestUtil.TestChildNativePath, "ReportSignal") { StdInputRedirection = InputRedirection.InputPipe, StdOutputRedirection = OutputRedirection.OutputPipe, Flags = ChildProcessFlags.AttachToCurrentConsole, }; using var sut = ChildProcess.Start(si); Assert.False(sut.CanSignal); Assert.Throws<InvalidOperationException>(() => sut.SignalInterrupt()); Assert.Throws<InvalidOperationException>(() => sut.SignalTermination()); Assert.Equal('R', sut.StandardOutput.ReadByte()); sut.Kill(); sut.WaitForExit(); Assert.NotEqual(0, sut.ExitCode); }
public async Task ConnectOutputAndErrorPipes() { { var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoOutAndError") { StdOutputRedirection = OutputRedirection.OutputPipe, StdErrorRedirection = OutputRedirection.ErrorPipe, }; using var sut = ChildProcess.Start(si); await Impl(sut, "TestChild.Out", "TestChild.Error"); } { // invert stdout and stderr var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoOutAndError") { StdOutputRedirection = OutputRedirection.ErrorPipe, StdErrorRedirection = OutputRedirection.OutputPipe, }; using var sut = ChildProcess.Start(si); await Impl(sut, "TestChild.Error", "TestChild.Out"); }
private static IChildProcess CreateProcessTree(AnonymousPipeServerStream stdOutputPipe) { var si = new ChildProcessStartInfo( TestUtil.DotnetCommandName, TestUtil.TestChildPath, "SpawnAndWait", TestUtil.DotnetCommandName, TestUtil.TestChildPath, "EchoAndSleepAndEcho", "S", SleepMilliseconds, "Exited") { StdInputRedirection = InputRedirection.NullDevice, StdOutputRedirection = OutputRedirection.Handle, StdOutputHandle = stdOutputPipe.ClientSafePipeHandle, StdErrorRedirection = OutputRedirection.NullDevice, }; var p = ChildProcess.Start(si); try { stdOutputPipe.DisposeLocalCopyOfClientHandle(); // Wait for the grand child to echo. Assert.Equal((byte)'S', stdOutputPipe.ReadByte()); } catch { p.Dispose(); throw; } return(p); }