/// <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="IOException">Failed to open a specified file.</exception>
        /// <exception cref="ProcessCreationFailedException">Process creation failed.</exception>
        public static ChildProcess Start(ChildProcessStartInfo startInfo)
        {
            startInfo = startInfo ?? throw new ArgumentNullException(nameof(startInfo));

            using (var stdHandles = new PipelineStdHandleCreator(startInfo))
            {
                var processHandle = ProcessPal.SpawnProcess(
                    fileName: startInfo.FileName,
                    arguments: startInfo.Arguments,
                    workingDirectory: startInfo.WorkingDirectory,
                    environmentVariables: startInfo.EnvironmentVariables,
                    stdIn: stdHandles.PipelineStdIn,
                    stdOut: stdHandles.PipelineStdOut,
                    stdErr: stdHandles.PipelineStdErr);

                try
                {
                    var process = new ChildProcess(processHandle, stdHandles.InputStream, stdHandles.OutputStream, stdHandles.ErrorStream);
                    stdHandles.DetachStreams();
                    return(process);
                }
                catch
                {
                    processHandle.Dispose();
                    throw;
                }
            }
        }
示例#2
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.HasCreateNewConsole())
            {
                throw new ArgumentException(
                          $"{nameof(ChildProcessFlags.UseCustomCodePage)} requires {nameof(ChildProcessFlags.CreateNewConsole)}.", nameof(startInfo));
            }

            var resolvedPath = ResolveExecutablePath(startInfoInternal.FileName, startInfoInternal.Flags);

            using var stdHandles = new PipelineStdHandleCreator(ref startInfoInternal);
            IChildProcessStateHolder processState;

            try
            {
                processState = ChildProcessContext.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);
        }
示例#3
0
        /// <summary>
        /// Starts a process pipeline as specified in <paramref name="startInfo"/>.
        /// </summary>
        /// <remarks>
        /// Please note that <see cref="Start(ProcessPipelineStartInfo)"/> does not throw <see cref="ProcessCreationFailedException"/>
        /// when one of the child processes cannot be created. Instead <see cref="GetExitCodes"/> returns an exit code of null for such a process.
        /// </remarks>
        /// <param name="startInfo"><see cref="ProcessPipelineStartInfo"/>.</param>
        /// <returns>The started process pipeline.</returns>
        /// <exception cref="IOException">Failed to open a specified file.</exception>
        public static ProcessPipeline Start(ProcessPipelineStartInfo startInfo)
        {
            startInfo = startInfo ?? throw new ArgumentNullException(nameof(startInfo));

            if (startInfo.ProcessPipelineItems.Count == 0)
            {
                throw new ArgumentException("At least one item must be added to ProcessPipelineStartInfo.", nameof(startInfo));
            }

            using (var stdHandles = new PipelineStdHandleCreator(
                       startInfo.StdInputRedirection,
                       startInfo.StdOutputRedirection,
                       startInfo.StdErrorRedirection,
                       startInfo.StdInputFile,
                       startInfo.StdOutputFile,
                       startInfo.StdErrorFile,
                       startInfo.StdInputHandle,
                       startInfo.StdOutputHandle,
                       startInfo.StdErrorHandle))
            {
                var count           = startInfo.ProcessPipelineItems.Count;
                var entries         = new ProcessEntry[count];
                var interChildPipes = new (SafeFileHandle readPipe, SafeFileHandle writePipe)[count - 1];