Process.StandardOutput.Read Blocks Asynchronous Behavior?

  • Thread starter Thread starter Al Cohen
  • Start date Start date
A

Al Cohen

I'll start by warning that I'm a newbie to C# (but I've been programming
for 25 years), so I may just be doing something reallyreally dumb.

I'm writing a C# wrapper for a command-line application (pscp.exe, a
secure file-copy app that's part of the excellent PuTTY SSH package).

Getting pscp.exe to run properly was a piece of cake using the
System.Diagnostics.Process class.

The thing that I can't get to work is the ability to read pscp.exe's
standard output on the fly. Every second or so, pscp.exe sends progress
information to the standard output: %completed, estimated time
remaining, and so forth. I'd like to capture this as it happens and
update a progress bar on my Windows app. In principle, this should be
fine since, as I understand things, applications run using
System.Diagnostics.Process are run asynchronously.

To avoid eating all of the CPU time, I set up a scheme using a timer to
periodically fire and read anything new from StandardOutput stream, as
follows:

- Start pscp.exe using Process.Start
- enable timer

- when timer fires:
-- read all new characters in StandardOutput
-- parse the characters for progress information
-- if pscp.exe has exited, disable timer

I've used this type of scheme many times before in real-time programming.

Here's the problem: the first time I call Process.StandardOutput.Read,
my app stops and waits at that line for pscp.exe to exit. By contrast,
if I have the timer just write to a window and test if pscp.exe has
exited (no Process.StandardOutput.Read), all works as expected: the
timer times out periodically and stuff get's written to the screen on
each timeout.

Here is the current version of the offending code segment (I've tried it
a few different ways now, none worked):

public static string UpdateXferStatus()
{
int i;
string incoming = "";
int numCharsRead;
bool endOfInput = false;
while(endOfInput == false)
{
char[] inChars = new char[100];
//freezes at next line until pscp.exe exits
numCharsRead = PProcess.StandardOutput.Read(inChars, 0, 100);
if (numCharsRead > 0)
{
for (i=0; i!=numCharsRead; i++)
{
incoming = incoming + inChars;
}
}
else
{
endOfInput=true;
}
}

return incoming;
}

I've tried two variations of the StandardOutput.Read method, with
similar results.

Any help would be GREATLY appreciated!

Thanks in advance,

Al Cohen
www.alcohen.com
 
Thanks Michael!

I'll try launching a second thread to monitor StandardOutput. The MS
docs are a pretty vague (or I'm pretty dense), but they seem to indicate
that new threads are needed only for reading both StandardOutput and
StandardError simultaneously. I'm only monitoring StandardOutput.

Best regards,

Al Cohen
 
Tried launching a seperate thread for reading the standard output - this
thread hangs until the DOS executable completes, at which point the
entire standard output for the run is available from StandardOutput.

So, I still can't do what I want.

Is it possible that the DOS executable is doing something naughty?

Thanks,

Al Cohen
 
Al Cohen said:
Tried launching a seperate thread for reading the standard output - this
thread hangs until the DOS executable completes, at which point the
entire standard output for the run is available from StandardOutput.

So, I still can't do what I want.

Is it possible that the DOS executable is doing something naughty?

Sounds odd indeed.

Are you still using StandardOutput.Read ( )? Have you tried ReadLine? I'm
not an expert on StreamReader's so I can't give you advice on the subtle
details of how Read works.

Now that you have a separate thread for reading, you should be able to block
on ReadLine(), and do something everytime you get a complete line.

I would try hard to narrow it down to your C# app or the executable you are
running. I might suggest (if you haven't alreayd) downloading my code
from:
http://www.codeproject.com/useritems/LaunchProcess.asp

There is a small ConsoleApp in there that you can run from your C# app to
see if you are correctly capturing the standard out. (You can modify this
one to sleep between output statements, etc). Or find some other console
app and try running it.

You can also try to exectute your dos executable from my C# program. See if
both / either of these work.

I suppose it's possible that an application could cache it's standard out
and not return anything until it's finished, but I would think this would be
very apparant if you just ran the program from command line.

Maybe, if it's not too big, you can post your code again?
 
Back
Top