I have following use case. I have created one EXE in from Unmanned C++. let say printing 1 - 100 on console. output is captured into below output callback
List<int> a = new List<int>();
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
a.add(Convert.ToInt(e.Data));
}
However I want to use IEnumerable and yield return of e.Data. Considering the C++ exe will have it's own execution thread it won't wait for it provide the control. I will have to wait for it's execution to finish. I can capture everything and prepare a list. then I can yield items one by one. My question to you is there any known mechanism or way to do this while the process is running? what can I change in my C++ code? so that it allows me to control this back and forth? Consider this process is running under one function on the C# side.
The next approach can be used to read the output of the external process while it is running:
var proc = new Process
{
StartInfo =
{
FileName = "process_name.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
},
// Set this property to true to enable external
// process raise notification that is has exited.
EnableRaisingEvents = true
};
// BlockingCollection is a thread safe producer-consumer
// collection. We use it to collect the output of the
// external process and to process it while the process
// is running.
var lines = new BlockingCollection<string>();
proc.OutputDataReceived += (s, e) =>
{
// Here we collect the output of the external process.
if (!string.IsNullOrEmpty(e.Data))
lines.Add(e.Data);
};
// This event is raised when external process exits.
proc.Exited += (s, e) =>
{
// Here we notify our BlockingCollection that no more
// data to process is available.
lines.CompleteAdding();
};
proc.Start();
proc.BeginOutputReadLine();
// Here we start to process the output of the external process
// without waiting for it to exit.
// This loop iterates over the items produced by the
// BlockingCollection until method CompleteAdding is called.
// This loop is being executed while external process is
// running and finishes when the process exits.
foreach (string line in lines.GetConsumingEnumerable())
{
Console.WriteLine(line);
}
// Here we do not need to call proc.WaitForExit(), because
// loop over lines collection finishes when proc exits.
Here are links to learn to understand this code sample:
Process.EnableRaisingEvents
Process.Exited
BlockingCollection
BlockingCollection.CompleteAdding
BlockingCollection.GetConsumingEnumerable
For convenience, we can create a method that starts external process and immediately returns IEnumerable
object that can be used to loop over the output data of the process:
private static IEnumerable<string> ReadOutput(string procFileName)
{
var proc = new Process
{
StartInfo =
{
FileName = procFileName,
UseShellExecute = false,
RedirectStandardOutput = true,
},
EnableRaisingEvents = true
};
var lines = new BlockingCollection<string>();
proc.OutputDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
lines.Add(e.Data);
};
proc.Exited += (s, e) =>
{
lines.CompleteAdding();
};
proc.Start();
proc.BeginOutputReadLine();
return lines.GetConsumingEnumerable();
}
And then we can use this method when we need to run external process and read its output as soon as output data becomes available:
public static void Demo()
{
foreach (string line in ReadOutput("process_name.exe"))
{
Console.WriteLine(line);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.