Skip to content

Commit c70a24a

Browse files
committed
feat: add ProcessId for CommandResult
1 parent 8459139 commit c70a24a

File tree

2 files changed

+93
-33
lines changed

2 files changed

+93
-33
lines changed

src/WeihanLi.Common/Extensions/ProcessExtension.cs

Lines changed: 92 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,23 @@ public static CommandResult GetResult(this ProcessStartInfo psi)
9393
using var stdOut = new StringWriter(stdOutStringBuilder);
9494
var stdErrStringBuilder = new StringBuilder();
9595
using var stdErr = new StringWriter(stdErrStringBuilder);
96-
var exitCode = GetExitCode(psi, stdOut, stdErr);
97-
return new CommandResult(exitCode, stdOutStringBuilder.ToString(), stdErrStringBuilder.ToString());
96+
var exitCode = -1;
97+
int? processId = null;
98+
Action<Process> processStartAction = p => processId = p.Id;
99+
100+
try
101+
{
102+
using var process = psi.ExecuteProcess(stdOut, stdErr, processStartAction);
103+
exitCode = process.ExitCode;
104+
}
105+
catch (Win32Exception win32Exception)
106+
{
107+
exitCode = win32Exception.ErrorCode;
108+
}
109+
return new(exitCode, stdOutStringBuilder.ToString(), stdErrStringBuilder.ToString())
110+
{
111+
ProcessId = processId
112+
};
98113
}
99114

100115
/// <summary>
@@ -107,16 +122,30 @@ public static async Task<CommandResult> GetResultAsync(this ProcessStartInfo psi
107122
{
108123
var stdOutStringBuilder = new StringBuilder();
109124
#if NETSTANDARD2_1 || NET6_0_OR_GREATER
110-
await
125+
await
111126
#endif
112127
using var stdOut = new StringWriter(stdOutStringBuilder);
113128
var stdErrStringBuilder = new StringBuilder();
114129
#if NETSTANDARD2_1 || NET6_0_OR_GREATER
115-
await
130+
await
116131
#endif
117132
using var stdErr = new StringWriter(stdErrStringBuilder);
118-
var exitCode = await GetExitCodeAsync(psi, stdOut, stdErr, cancellationToken);
119-
return new(exitCode, stdOutStringBuilder.ToString(), stdErrStringBuilder.ToString());
133+
var exitCode = -1;
134+
int? processId = null;
135+
Action<Process> processStartAction = p => processId = p.Id;
136+
try
137+
{
138+
using var process = await psi.ExecuteProcessAsync(stdOut, stdErr, processStartAction.WrapTask(), cancellationToken);
139+
exitCode = process.ExitCode;
140+
}
141+
catch (Win32Exception win32Exception)
142+
{
143+
exitCode = win32Exception.ErrorCode;
144+
}
145+
return new(exitCode, stdOutStringBuilder.ToString(), stdErrStringBuilder.ToString())
146+
{
147+
ProcessId = processId
148+
};
120149
}
121150

122151
/// <summary>
@@ -128,11 +157,48 @@ public static async Task<CommandResult> GetResultAsync(this ProcessStartInfo psi
128157
/// <returns>Process exit code</returns>
129158
public static int GetExitCode(this ProcessStartInfo psi, TextWriter? stdOut = null,
130159
TextWriter? stdErr = null)
160+
{
161+
try
162+
{
163+
using var process = psi.ExecuteProcess(stdOut, stdErr);
164+
return process.ExitCode;
165+
}
166+
catch (Win32Exception win32Exception)
167+
{
168+
return win32Exception.ErrorCode;
169+
}
170+
}
171+
172+
/// <summary>
173+
/// Wait for process exit and get exit code
174+
/// </summary>
175+
/// <param name="psi">Process is started from this information</param>
176+
/// <param name="stdOut">Defaults to Console.Out</param>
177+
/// <param name="stdErr">Defaults to Console.Error</param>
178+
/// <param name="processStartAction"></param>
179+
/// <param name="cancellationToken">cancellationToken</param>
180+
/// <returns>Process exit code</returns>
181+
public static async Task<int> GetExitCodeAsync(this ProcessStartInfo psi, TextWriter? stdOut = null,
182+
TextWriter? stdErr = null, CancellationToken cancellationToken = default)
183+
{
184+
try
185+
{
186+
using var process = await psi.ExecuteProcessAsync(stdOut, stdErr, null, cancellationToken);
187+
return process.ExitCode;
188+
}
189+
catch (Win32Exception win32Exception)
190+
{
191+
return win32Exception.ErrorCode;
192+
}
193+
}
194+
195+
public static Process ExecuteProcess(this ProcessStartInfo psi, TextWriter? stdOut = null,
196+
TextWriter? stdErr = null, Action<Process>? processStartAction = null)
131197
{
132198
psi.RedirectStandardOutput = stdOut != null;
133199
psi.RedirectStandardError = stdErr != null;
134-
psi.UseShellExecute = false;
135-
using var process = new Process();
200+
201+
var process = new Process();
136202
process.StartInfo = psi;
137203
process.OutputDataReceived += (_, e) =>
138204
{
@@ -145,69 +211,62 @@ public static int GetExitCode(this ProcessStartInfo psi, TextWriter? stdOut = nu
145211
stdErr?.WriteLine(e.Data);
146212
};
147213

148-
try
149-
{
150-
process.Start();
151-
}
152-
catch (Win32Exception win32Exception)
153-
{
154-
return win32Exception.ErrorCode;
155-
}
214+
process.Start();
215+
processStartAction?.Invoke(process);
156216

157217
process.BeginOutputReadLine();
158218
process.BeginErrorReadLine();
159219
process.WaitForExit();
160220

161-
return process.ExitCode;
221+
return process;
162222
}
163223

164224
/// <summary>
165-
/// Wait for process exit and get exit code
225+
/// Execute process
166226
/// </summary>
167227
/// <param name="psi">Process is started from this information</param>
168228
/// <param name="stdOut">Defaults to Console.Out</param>
169229
/// <param name="stdErr">Defaults to Console.Error</param>
230+
/// <param name="processStartAction">Action to execute when process start</param>
170231
/// <param name="cancellationToken">cancellationToken</param>
171232
/// <returns>Process exit code</returns>
172-
public static async Task<int> GetExitCodeAsync(this ProcessStartInfo psi, TextWriter? stdOut = null,
173-
TextWriter? stdErr = null, CancellationToken cancellationToken = default)
233+
public static async Task<Process> ExecuteProcessAsync(this ProcessStartInfo psi, TextWriter? stdOut = null,
234+
TextWriter? stdErr = null, Func<Process, Task>? processStartAction = null, CancellationToken cancellationToken = default)
174235
{
175236
psi.RedirectStandardOutput = stdOut != null;
176237
psi.RedirectStandardError = stdErr != null;
177-
psi.UseShellExecute = false;
178-
using var process = new Process();
238+
239+
var process = new Process();
179240
process.StartInfo = psi;
180-
var stdOutComplete = new TaskCompletionSource<object?>();
181-
var stdErrComplete = new TaskCompletionSource<object?>();
241+
var stdOutComplete = new TaskCompletionSource();
242+
var stdErrComplete = new TaskCompletionSource();
182243
process.OutputDataReceived += (_, e) =>
183244
{
184245
if (e.Data != null)
185246
stdOut?.WriteLine(e.Data);
186247
else
187-
stdOutComplete.SetResult(null);
248+
stdOutComplete.SetResult();
188249
};
189250
process.ErrorDataReceived += (_, e) =>
190251
{
191252
if (e.Data != null)
192253
stdErr?.WriteLine(e.Data);
193254
else
194-
stdErrComplete.SetResult(null);
255+
stdErrComplete.SetResult();
195256
};
196-
try
197-
{
198-
process.Start();
199-
}
200-
catch (Win32Exception win32Exception)
257+
258+
process.Start();
259+
if (processStartAction is not null)
201260
{
202-
return win32Exception.ErrorCode;
261+
await processStartAction.Invoke(process);
203262
}
204263

205264
process.BeginOutputReadLine();
206265
process.BeginErrorReadLine();
207266
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ApplicationHelper.ExitToken);
208267
cts.Token.Register((p) => ((Process)p!).TryKill(), process);
209268
await Task.WhenAll(process.WaitForExitAsync(cts.Token), stdOutComplete.Task, stdErrComplete.Task);
210-
return process.ExitCode;
269+
return process;
211270
}
212271

213272
/// <summary>

src/WeihanLi.Common/Helpers/CommandExecutor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ public sealed class CommandResult(int exitCode, string standardOut, string stand
264264
public string StandardOut { get; } = standardOut;
265265
public string StandardError { get; } = standardError;
266266
public int ExitCode { get; } = exitCode;
267+
public int? ProcessId { get; set; }
267268

268269
public CommandResult EnsureSuccessExitCode(int successCode = 0)
269270
{

0 commit comments

Comments
 (0)