示例#1
0
        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;
            }
示例#2
0
        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);
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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));
        }
示例#8
0
        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);
            }
示例#10
0
        /// <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);
        }
示例#12
0
        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);
        }
示例#14
0
        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);
        }
示例#16
0
        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");
            }
示例#17
0
        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);
        }