Skip to content

Add StandardInput/Output/Error SafeFileHandle properties and LeaveHandlesOpen to ProcessStartInfo#125848

Draft
Copilot wants to merge 5 commits intocopilot/refactor-startcore-method-argumentsfrom
copilot/add-standard-input-output-properties
Draft

Add StandardInput/Output/Error SafeFileHandle properties and LeaveHandlesOpen to ProcessStartInfo#125848
Copilot wants to merge 5 commits intocopilot/refactor-startcore-method-argumentsfrom
copilot/add-standard-input-output-properties

Conversation

Copy link
Contributor

Copilot AI commented Mar 20, 2026

Description

Adds three new SafeFileHandle? properties and a LeaveHandlesOpen property to ProcessStartInfo that allow passing file handles directly to child processes, bypassing the RedirectStandard* pipe-based mechanism.

var psi = new ProcessStartInfo("grep") { ArgumentList = { "test" } };
SafeFileHandle.CreateAnonymousPipe(out SafeFileHandle readPipe, out SafeFileHandle writePipe);
psi.StandardInput = readPipe;
psi.StandardOutput = File.OpenHandle("output.txt", FileMode.Create, FileAccess.Write);
Process.Start(psi);

By default, Process.Start disposes the standard handles after starting the child process. Set LeaveHandlesOpen to true to keep them open for the caller to manage.

Changes

  • ProcessStartInfo.cs: New StandardInput, StandardOutput, StandardError auto-properties (SafeFileHandle?) with XML docs. Remarks document that handles do not need to be inheritable (the runtime handles that), and list typical APIs (SafeFileHandle.CreateAnonymousPipe, File.OpenHandle, File.OpenNullHandle, Console.OpenStandardInputHandle/OpenStandardOutputHandle/OpenStandardErrorHandle), interaction with LeaveHandlesOpen, and constraints. New LeaveHandlesOpen property (bool, default false) controlling whether handles are disposed after process start.
  • ref/System.Diagnostics.Process.cs: Public API surface additions for StandardInput, StandardOutput, StandardError, and LeaveHandlesOpen
  • Process.cs validation: When any StandardX handle is set, UseShellExecute must be false and the corresponding RedirectStandardX must also be false. Reuses existing SR.CantRedirectStreams error message for the UseShellExecute check.
  • Process.cs pipe creation: New handles take priority over default stdin/stdout/stderr inheritance. Handles are always disposed after starting the child process unless LeaveHandlesOpen is true.
  • Strings.resx: New error string CantSetHandleAndRedirect
  • ProcessHandlesTests.cs: Tests for pipe redirection, inherited handles, piping, and validation error cases

💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copilot AI and others added 3 commits March 20, 2026 17:30
…artInfo

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
{
if (startInfo.UseShellExecute)
{
throw new InvalidOperationException(SR.CantUseHandlesWithShellExecute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's re-use existing error message:

Suggested change
throw new InvalidOperationException(SR.CantUseHandlesWithShellExecute);
throw new InvalidOperationException(SR.CantRedirectStreams);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 60844f3 — now reuses SR.CantRedirectStreams and removed the unused CantUseHandlesWithShellExecute string from Strings.resx.

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
See info in area-owners.md if you want to be subscribed.

@adamsitnik adamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Mar 20, 2026
/// When set, the handle is passed directly to the child process and <see cref="RedirectStandardInput"/> must be <see langword="false"/>.
/// </summary>
/// <value>A <see cref="SafeFileHandle"/> to use as the standard input handle of the child process, or <see langword="null"/> to use the default behavior.</value>
public SafeFileHandle? StandardInput { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any requirements around its inheritability that should be called out in the docs?

Maybe add some XML comments remarks around when this would be used, what APIs it might typically used in conjunction with, etc.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added <remarks> sections to all three properties in 60844f3 covering: inheritability requirement, typical APIs to use (SafeFileHandle.CreateAnonymousPipe, File.OpenHandle), interaction with the new LeaveHandlesOpen property, and constraints (RedirectStandard* / UseShellExecute).

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address all the feedback

Comment on lines +112 to +118
using SafeFileHandle inputHandle = Console.OpenStandardInputHandle();
using SafeFileHandle outputHandle = Console.OpenStandardOutputHandle();
using SafeFileHandle errorHandle = Console.OpenStandardErrorHandle();

startInfo.StandardInput = inputHandle;
startInfo.StandardOutput = outputHandle;
startInfo.StandardError = errorHandle;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let the new property dispose all these handles for us.

Suggested change
using SafeFileHandle inputHandle = Console.OpenStandardInputHandle();
using SafeFileHandle outputHandle = Console.OpenStandardOutputHandle();
using SafeFileHandle errorHandle = Console.OpenStandardErrorHandle();
startInfo.StandardInput = inputHandle;
startInfo.StandardOutput = outputHandle;
startInfo.StandardError = errorHandle;
startInfo.StandardInput = Console.OpenStandardInputHandle();
startInfo.StandardOutput = Console.OpenStandardOutputHandle();
startInfo.StandardError = Console.OpenStandardErrorHandle();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 60844f3 — removed the using statements; handles are now disposed by Process.Start since LeaveHandlesOpen defaults to false.

…pen property, improve XML docs

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9f61c68e-edfd-42e9-b86b-bfb9ee7d8946
Copilot AI changed the title Add StandardInput/Output/Error SafeFileHandle properties to ProcessStartInfo Add StandardInput/Output/Error SafeFileHandle properties and LeaveHandlesOpen to ProcessStartInfo Mar 20, 2026
Copilot AI requested a review from adamsitnik March 20, 2026 23:00
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

/// </summary>
/// <remarks>
/// <para>
/// The handle must be inheritable. Use <see cref="SafeFileHandle.CreateAnonymousPipe"/> to create a pair of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be inheritable, because other process may inherit it by accident before we get here.

Also, do mention File.OpenNullHandle and Console.OpenSatndardInputHandle API

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in c8b8723 — the docs now state the handle does not need to be inheritable (runtime handles that). Also added mentions of File.OpenNullHandle and Console.OpenStandardInputHandle / OpenStandardOutputHandle / OpenStandardErrorHandle for each respective property.

using Process process = Process.Start(startInfo)!;

// Close the parent copy of the child handle, so the pipe will signal EOF when the child exits
writePipe.Close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in c8b8723Process.Start closes it now since LeaveHandlesOpen defaults to false.


// Close the parent copy of the child handles, so the pipes will signal EOF when the child exits
outputWrite.Close();
errorWrite.Close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in c8b8723.

…ullHandle/OpenStandard*Handle APIs, remove redundant Close() calls

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/29b43a66-dcf9-47b0-95df-28d834129305
Copilot AI requested a review from adamsitnik March 20, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Diagnostics.Process NO-REVIEW Experimental/testing PR, do NOT review it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants