/// <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; } } }
/// <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); }
/// <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];