views:

313

answers:

2

I'm using the data ready events of the Process class to get information from the standard output and standard error of a running process.

It works great on the first run, but after calling Stop() then Start() to force a restart of the application, I no longer recieve data. I've tried CancelErrorRead() but no luck there.

I'm considering just re-instantiating the object every time I need to re-run the app, but it seems silly to need to do that.

Any advice on how to re-use a Process object to restart a stopped process?

Relevant code chunks:

Constructor:

   ProcessStartInfo objStartInfo = new ProcessStartInfo();
    objStartInfo.CreateNoWindow = true;
    objStartInfo.RedirectStandardInput = true;
    objStartInfo.RedirectStandardOutput = true;
    objStartInfo.RedirectStandardError = true;
    objStartInfo.UseShellExecute = false;

    objClient = new Process();
    objClient.StartInfo = objStartInfo;

    objClient.EnableRaisingEvents = true;
    objClient.OutputDataReceived   += new DataReceivedEventHandler(read);
    objClient.ErrorDataReceived    += new DataReceivedEventHandler(error);

Start:

    objClient.StartInfo.FileName    = strAppPath;
    objClient.StartInfo.Arguments   = strArgs;
    start();
    objClient.BeginErrorReadLine();
    objClient.BeginOutputReadLine();

Stop:

    objClient.Close();
    objClient.CancelErrorRead();
    objClient.CancelOutputRead();
A: 

According to msdn you should call BeginOutputReadLine and BeginErrorReadLine to enable asynchronous reads from StandardOutput or StandardError using events.

Have a look at the remarks section on BeginOutputReadLine

Mehmet Ergut
Indeed I do! I seem to have forgotten to paste those in there.The problem is that those two functions can be called only once, a second call throws an exception, and calling CancelErrorRead() before calling them again doesn't really allow me to recapture the outputs.
RandomInsano
Looks like creating new Process objects is the only way out as Michael suggested.
Mehmet Ergut
+1  A: 

Your Process object is not associated with a process until you call Start() (or use one of the static methods off Process). A stopped/closed process is functionally the same as no process at all. Given that, it's hard to believe there's any overhead to creating a new Process object, when compared to the (relatively enormous) cost of creating processes on Windows. Just create new Process objects as needed.

Michael Petrotta
That's a good call. Is there a way to see if the garbage collector cleans up my objects? Do I need to remove the event handlers before it will be collected? I think that's the case in JavaScript.
RandomInsano
It's probably true that creating a new Process object each time is not that expensive but I think that's not the solution. Getting around the problem like that may cause unexpected behaviour afterwards. Given the code sample and documentation, calls to BeginOutputReadLine and BeginErrorReadLine are missing.
Mehmet Ergut
@Mehmet: agreed your recommendations are good, but the above is not "working around the problem", it's the correct way to interface with processes in .NET.
Michael Petrotta
@RandomInsano: It's good practice to remove your event handlers, but it's not necessary in this case. see http://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occuring
Michael Petrotta
@Michael Petrotta - Thanks. Good reading@All - Updated code to include the BeginErrorReadLine stuff. Forgot to add that before.
RandomInsano
@Michael: didn't mean to sound harsh, got stuck on the missing method calls, it's late over here :| On second thought, it may be that the Process class not reinitializing correctly the asynchronous streams once it's closed.
Mehmet Ergut