@@ -25,7 +25,7 @@ public static Task WaitForExitAsync(this Process process, CancellationToken canc
25
25
{
26
26
Guard . NotNull ( process ) ;
27
27
process . EnableRaisingEvents = true ;
28
- var tcs = new TaskCompletionSource < object ? > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
28
+ var tcs = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
29
29
try
30
30
{
31
31
process . Exited += EventHandler ;
@@ -47,7 +47,7 @@ public static Task WaitForExitAsync(this Process process, CancellationToken canc
47
47
48
48
return tcs . Task ;
49
49
50
- void EventHandler ( object o , EventArgs eventArgs ) => tcs . TrySetResult ( null ) ;
50
+ void EventHandler ( object o , EventArgs eventArgs ) => tcs . TrySetResult ( ) ;
51
51
}
52
52
#endif
53
53
@@ -93,8 +93,23 @@ public static CommandResult GetResult(this ProcessStartInfo psi)
93
93
using var stdOut = new StringWriter ( stdOutStringBuilder ) ;
94
94
var stdErrStringBuilder = new StringBuilder ( ) ;
95
95
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
+ } ;
98
113
}
99
114
100
115
/// <summary>
@@ -107,16 +122,30 @@ public static async Task<CommandResult> GetResultAsync(this ProcessStartInfo psi
107
122
{
108
123
var stdOutStringBuilder = new StringBuilder ( ) ;
109
124
#if NETSTANDARD2_1 || NET6_0_OR_GREATER
110
- await
125
+ await
111
126
#endif
112
127
using var stdOut = new StringWriter ( stdOutStringBuilder ) ;
113
128
var stdErrStringBuilder = new StringBuilder ( ) ;
114
129
#if NETSTANDARD2_1 || NET6_0_OR_GREATER
115
- await
130
+ await
116
131
#endif
117
132
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
+ } ;
120
149
}
121
150
122
151
/// <summary>
@@ -128,11 +157,55 @@ public static async Task<CommandResult> GetResultAsync(this ProcessStartInfo psi
128
157
/// <returns>Process exit code</returns>
129
158
public static int GetExitCode ( this ProcessStartInfo psi , TextWriter ? stdOut = null ,
130
159
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="cancellationToken">cancellationToken</param>
179
+ /// <returns>Process exit code</returns>
180
+ public static async Task < int > GetExitCodeAsync ( this ProcessStartInfo psi , TextWriter ? stdOut = null ,
181
+ TextWriter ? stdErr = null , CancellationToken cancellationToken = default )
182
+ {
183
+ try
184
+ {
185
+ using var process = await psi . ExecuteProcessAsync ( stdOut , stdErr , null , cancellationToken ) ;
186
+ return process . ExitCode ;
187
+ }
188
+ catch ( Win32Exception win32Exception )
189
+ {
190
+ return win32Exception . ErrorCode ;
191
+ }
192
+ }
193
+
194
+ /// <summary>
195
+ /// Execute process
196
+ /// </summary>
197
+ /// <param name="psi">Process is started from this information</param>
198
+ /// <param name="stdOut">Defaults to Console.Out</param>
199
+ /// <param name="stdErr">Defaults to Console.Error</param>
200
+ /// <param name="processStartAction">Action to execute when process start</param>
201
+ /// <returns>Process executed</returns>
202
+ public static Process ExecuteProcess ( this ProcessStartInfo psi , TextWriter ? stdOut = null ,
203
+ TextWriter ? stdErr = null , Action < Process > ? processStartAction = null )
131
204
{
132
205
psi . RedirectStandardOutput = stdOut != null ;
133
206
psi . RedirectStandardError = stdErr != null ;
134
- psi . UseShellExecute = false ;
135
- using var process = new Process ( ) ;
207
+
208
+ var process = new Process ( ) ;
136
209
process . StartInfo = psi ;
137
210
process . OutputDataReceived += ( _ , e ) =>
138
211
{
@@ -145,69 +218,62 @@ public static int GetExitCode(this ProcessStartInfo psi, TextWriter? stdOut = nu
145
218
stdErr ? . WriteLine ( e . Data ) ;
146
219
} ;
147
220
148
- try
149
- {
150
- process . Start ( ) ;
151
- }
152
- catch ( Win32Exception win32Exception )
153
- {
154
- return win32Exception . ErrorCode ;
155
- }
221
+ process . Start ( ) ;
222
+ processStartAction ? . Invoke ( process ) ;
156
223
157
224
process . BeginOutputReadLine ( ) ;
158
225
process . BeginErrorReadLine ( ) ;
159
226
process . WaitForExit ( ) ;
160
227
161
- return process . ExitCode ;
228
+ return process ;
162
229
}
163
230
164
231
/// <summary>
165
- /// Wait for process exit and get exit code
232
+ /// Execute process
166
233
/// </summary>
167
234
/// <param name="psi">Process is started from this information</param>
168
235
/// <param name="stdOut">Defaults to Console.Out</param>
169
236
/// <param name="stdErr">Defaults to Console.Error</param>
237
+ /// <param name="processStartAction">Action to execute when process start</param>
170
238
/// <param name="cancellationToken">cancellationToken</param>
171
239
/// <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 )
240
+ public static async Task < Process > ExecuteProcessAsync ( this ProcessStartInfo psi , TextWriter ? stdOut = null ,
241
+ TextWriter ? stdErr = null , Func < Process , Task > ? processStartAction = null , CancellationToken cancellationToken = default )
174
242
{
175
243
psi . RedirectStandardOutput = stdOut != null ;
176
244
psi . RedirectStandardError = stdErr != null ;
177
- psi . UseShellExecute = false ;
178
- using var process = new Process ( ) ;
245
+
246
+ var process = new Process ( ) ;
179
247
process . StartInfo = psi ;
180
- var stdOutComplete = new TaskCompletionSource < object ? > ( ) ;
181
- var stdErrComplete = new TaskCompletionSource < object ? > ( ) ;
248
+ var stdOutComplete = new TaskCompletionSource ( ) ;
249
+ var stdErrComplete = new TaskCompletionSource ( ) ;
182
250
process . OutputDataReceived += ( _ , e ) =>
183
251
{
184
252
if ( e . Data != null )
185
253
stdOut ? . WriteLine ( e . Data ) ;
186
254
else
187
- stdOutComplete . SetResult ( null ) ;
255
+ stdOutComplete . SetResult ( ) ;
188
256
} ;
189
257
process . ErrorDataReceived += ( _ , e ) =>
190
258
{
191
259
if ( e . Data != null )
192
260
stdErr ? . WriteLine ( e . Data ) ;
193
261
else
194
- stdErrComplete . SetResult ( null ) ;
262
+ stdErrComplete . SetResult ( ) ;
195
263
} ;
196
- try
197
- {
198
- process . Start ( ) ;
199
- }
200
- catch ( Win32Exception win32Exception )
264
+
265
+ process . Start ( ) ;
266
+ if ( processStartAction is not null )
201
267
{
202
- return win32Exception . ErrorCode ;
268
+ await processStartAction . Invoke ( process ) ;
203
269
}
204
270
205
271
process . BeginOutputReadLine ( ) ;
206
272
process . BeginErrorReadLine ( ) ;
207
273
using var cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken , ApplicationHelper . ExitToken ) ;
208
274
cts . Token . Register ( ( p ) => ( ( Process ) p ! ) . TryKill ( ) , process ) ;
209
275
await Task . WhenAll ( process . WaitForExitAsync ( cts . Token ) , stdOutComplete . Task , stdErrComplete . Task ) ;
210
- return process . ExitCode ;
276
+ return process ;
211
277
}
212
278
213
279
/// <summary>
0 commit comments