Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>As far I understand, you want to preserve the order of stdout/stderr messages. I don't see any DECENT way to do this with C# managed Process(reflection - yes, nasty subclassing hacking - yes). It seems that it's pretty much hardcoded. </p> <p>This functionality does not depend on threads themselves. If you want to keep the order, <code>STDOUT</code> and <code>STDERROR</code> have to use same handle(buffer). If they use the same buffer, it's going to be synchronized.</p> <p>Here is a snippet from Process.cs:</p> <pre><code> if (startInfo.RedirectStandardOutput) { CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false); } else { startupInfo.hStdOutput = new SafeFileHandle( NativeMethods.GetStdHandle( NativeMethods.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false); } else { startupInfo.hStdError = new SafeFileHandle( NativeMethods.GetStdHandle( NativeMethods.STD_ERROR_HANDLE), false); } </code></pre> <p>as you can see, there are gonna be two buffers, and if we have two buffers, we have already lost the order information.</p> <p>Basically, you need to create your own Process() class that can handle this case. Sad? Yes. The good news is that it's not hard, it seems pretty simple. Here is a code taken from StackOverflow, not C# but enough to understand the algorithm:</p> <pre><code>function StartProcessWithRedirectedOutput(const ACommandLine: string; const AOutputFile: string; AShowWindow: boolean = True; AWaitForFinish: boolean = False): Integer; var CommandLine: string; StartupInfo: TStartupInfo; ProcessInformation: TProcessInformation; StdOutFileHandle: THandle; begin Result := 0; StdOutFileHandle := CreateFile(PChar(AOutputFile), GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); Win32Check(StdOutFileHandle &lt;&gt; INVALID_HANDLE_VALUE); try Win32Check(SetHandleInformation(StdOutFileHandle, HANDLE_FLAG_INHERIT, 1)); FillChar(StartupInfo, SizeOf(TStartupInfo), 0); FillChar(ProcessInformation, SizeOf(TProcessInformation), 0); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES; StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE); StartupInfo.hStdOutput := StdOutFileHandle; StartupInfo.hStdError := StdOutFileHandle; if not(AShowWindow) then begin StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_HIDE; end; CommandLine := ACommandLine; UniqueString(CommandLine); Win32Check(CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation)); try Result := ProcessInformation.dwProcessId; if AWaitForFinish then WaitForSingleObject(ProcessInformation.hProcess, INFINITE); finally CloseHandle(ProcessInformation.hProcess); CloseHandle(ProcessInformation.hThread); end; finally CloseHandle(StdOutFileHandle); end; end; </code></pre> <p>Source: <a href="https://stackoverflow.com/questions/19211958/how-to-redirect-large-amount-of-output-from-command-executed-by-createprocess">How to redirect large amount of output from command executed by CreateProcess?</a></p> <p>Instead of file, you want to use CreatePipe. From pipe, you can read asynchronously like so:</p> <pre><code>standardOutput = new StreamReader(new FileStream( standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); </code></pre> <p>and BeginReadOutput()</p> <pre><code> if (output == null) { Stream s = standardOutput.BaseStream; output = new AsyncStreamReader(this, s, new UserCallBack(this.OutputReadNotifyUser), standardOutput.CurrentEncoding); } output.BeginReadLine(); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload