Redirecting StandardOutput

M

Matt Burland

I'm having a problem with redirecting the StandardOutput of a process that I
use to run a DOS program in my application. The problem is that I when I
start my process (which I do in a separate thread) I can't read anything
from the stdout before the process actually finishes. If I do something like
this:

Process myProcess = new Process(myStartInfo)
// this gets shown straight away
MessageBox.Show("Process Started");
string s = myProcess.StandardOutput.Readline();
// this doesn't get shown until the process has finished
MessageBox.Show(s);
myProcess.WaitForExit();
// this gets shown immediately following the last MessageBox
MessageBox.Show("Process Finished");

It's clear that I'm not reading anything from the stdout before the process
has finished. This is a problem because the program I am running transfers
files to a server and can take a long time to finish, but I'm unable to give
the user any information about what is going on during the transfer.
Can somebody please tell me how to read the stdout without hanging up things
up until the process has finished? I can't believe there isn't a way to do
this!!

Cheers
 
J

Jon Skeet [C# MVP]

Matt Burland said:
I'm having a problem with redirecting the StandardOutput of a process that I
use to run a DOS program in my application. The problem is that I when I
start my process (which I do in a separate thread) I can't read anything
from the stdout before the process actually finishes. If I do something like
this:

Process myProcess = new Process(myStartInfo)
// this gets shown straight away
MessageBox.Show("Process Started");
string s = myProcess.StandardOutput.Readline();
// this doesn't get shown until the process has finished
MessageBox.Show(s);
myProcess.WaitForExit();
// this gets shown immediately following the last MessageBox
MessageBox.Show("Process Finished");

It's clear that I'm not reading anything from the stdout before the process
has finished. This is a problem because the program I am running transfers
files to a server and can take a long time to finish, but I'm unable to give
the user any information about what is going on during the transfer.
Can somebody please tell me how to read the stdout without hanging up things
up until the process has finished? I can't believe there isn't a way to do
this!!

I haven't seen this problem - is the standard output (not standard
error) definitely writing whole lines of text? Could you give a short
but complete example? (I remember writing a small "echo" program a
while ago which showed standard input and standard output working, for
example.)
 
M

Matt Burland

Okay, thanks for your response, here is a short test app I wrote that shows
the same behavior as the app I'm trying to write. The process I'm trying to
run is pscp.exe which can be downloaded from here:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
(NB: If anybody knows a better way to do scp to a unix box, I'd be
interested to here about it.)

using System;

using System.Diagnostics;

using System.Threading;

using System.IO;

namespace ProcessTest

{

class Class1

{

public string m_ProcessArgs;

public string m_ProcessApp;

public string m_Password;

public string m_UserID;

public string m_Address;

public string m_CalcPath;

public Process m_Running;

public StreamReader m_StdOut;

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main(string[] args)

{



Class1 myClass = new Class1();

myClass.m_UserID = "*******";

myClass.m_Address = "********"; // address of server

myClass.m_CalcPath = "/*********/"; // path on server

myClass.m_Password = "******";

myClass.PutFiles(@"C:\Data");

// ******* removed for security reasons!!

Console.ReadLine();

}

public void PutFiles(string FilePath)

{

m_ProcessArgs = "-r -pw " + m_Password + " " + FilePath + " " + m_UserID +
"@" + m_Address + ":" + m_CalcPath;

m_ProcessApp = "pscp.exe";

Console.WriteLine("Starting transfer thread");

Thread myThread = new Thread(new ThreadStart(TransferProcess));

myThread.Start();

Console.WriteLine("The transfer thread has been started");

}

private void TransferProcess()

{

ProcessStartInfo pInfo = new ProcessStartInfo(m_ProcessApp,m_ProcessArgs);

pInfo.UseShellExecute = false;

pInfo.RedirectStandardOutput = true;

pInfo.RedirectStandardError = true;

pInfo.CreateNoWindow = true;

m_Running = new Process();

m_Running.StartInfo = pInfo;

Console.WriteLine("TransferProcess is starting process....");

m_Running.Start();

// This line appears immediately

Console.WriteLine("The Process has started");

m_StdOut = m_Running.StandardOutput;

// This line doesn't appear until the process has completed

Console.WriteLine("This was read from the StdOut: " + m_StdOut.Read());

m_Running.WaitForExit();

// This appears immediately after the last line, indicating that the last
line wasn't displayed

// until the end of the process

Console.WriteLine("File Transfer Done");

Console.ReadLine();

}

}

}
 
M

Mr.Tickle

ewww, hungarian notation...



Matt Burland said:
Okay, thanks for your response, here is a short test app I wrote that shows
the same behavior as the app I'm trying to write. The process I'm trying to
run is pscp.exe which can be downloaded from here:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
(NB: If anybody knows a better way to do scp to a unix box, I'd be
interested to here about it.)

using System;

using System.Diagnostics;

using System.Threading;

using System.IO;

namespace ProcessTest

{

class Class1

{

public string m_ProcessArgs;

public string m_ProcessApp;

public string m_Password;

public string m_UserID;

public string m_Address;

public string m_CalcPath;

public Process m_Running;

public StreamReader m_StdOut;

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main(string[] args)

{



Class1 myClass = new Class1();

myClass.m_UserID = "*******";

myClass.m_Address = "********"; // address of server

myClass.m_CalcPath = "/*********/"; // path on server

myClass.m_Password = "******";

myClass.PutFiles(@"C:\Data");

// ******* removed for security reasons!!

Console.ReadLine();

}

public void PutFiles(string FilePath)

{

m_ProcessArgs = "-r -pw " + m_Password + " " + FilePath + " " + m_UserID +
"@" + m_Address + ":" + m_CalcPath;

m_ProcessApp = "pscp.exe";

Console.WriteLine("Starting transfer thread");

Thread myThread = new Thread(new ThreadStart(TransferProcess));

myThread.Start();

Console.WriteLine("The transfer thread has been started");

}

private void TransferProcess()

{

ProcessStartInfo pInfo = new ProcessStartInfo(m_ProcessApp,m_ProcessArgs);

pInfo.UseShellExecute = false;

pInfo.RedirectStandardOutput = true;

pInfo.RedirectStandardError = true;

pInfo.CreateNoWindow = true;

m_Running = new Process();

m_Running.StartInfo = pInfo;

Console.WriteLine("TransferProcess is starting process....");

m_Running.Start();

// This line appears immediately

Console.WriteLine("The Process has started");

m_StdOut = m_Running.StandardOutput;

// This line doesn't appear until the process has completed

Console.WriteLine("This was read from the StdOut: " + m_StdOut.Read());

m_Running.WaitForExit();

// This appears immediately after the last line, indicating that the last
line wasn't displayed

// until the end of the process

Console.WriteLine("File Transfer Done");

Console.ReadLine();

}

}

}


something
to
to
 
J

Jon Skeet [C# MVP]

Matt Burland said:
Okay, thanks for your response, here is a short test app I wrote that shows
the same behavior as the app I'm trying to write. The process I'm trying to
run is pscp.exe which can be downloaded from here:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
(NB: If anybody knows a better way to do scp to a unix box, I'd be
interested to here about it.)

I'm sure an SCP program could be written directly in C#, although I
don't know if there are any SSH utility classes easily available. That
might be your best approach though.

Given that pscp is already using ANSI escape sequences to update single
lines, my guess is that the standard output reader is basically getting
a bit confused. I don't know if pscp is specifically written to notice
that the output is being redirected or not - it could just be that it's
not being flushed until the end if so, or something like that. I can
find out for you if you want.
 
M

Matt Burland

Thanks for your help. I was starting to think it might be a problem with
pscp itself rather than anything I'm doing. I was also thinking it might be
something to do with how the Process class works. I know from the MSDN docs
that if you redirect the stdout and don't read it, then it can fill the pipe
up and hang the process. I was wondering if there isn't a minimum amount of
data that needs to be written to the pipe before it'll let you read anything
at all from the parent process? Something like the data is only transferred
to the parent process in blocks of some minimum size to avoid slowing both
processes down?
Along the lines of writing an SCP program directly in C#, I know the source
code for Putty is available (it's in C), but I'm not sure I'd know where to
start with it! Maybe if I find myself with a lot of extra time on my hands
I'll try and figure it out. Unfortunately, they don't have it available as a
DLL. If anybody does know of some (free) SSH utility classes that I can use
in my app I'd certainly be grateful. I tried searching online, but didn't
find anything.
 
M

Matt Burland

Thanks for your help. I was starting to think it might be a problem with
pscp itself rather than anything I'm doing. I was also thinking it might be
something to do with how the Process class works. I know from the MSDN docs
that if you redirect the stdout and don't read it, then it can fill the pipe
up and hang the process. I was wondering if there isn't a minimum amount of
data that needs to be written to the pipe before it'll let you read anything
at all from the parent process? Something like the data is only transferred
to the parent process in blocks of some minimum size to avoid slowing both
processes down?
Along the lines of writing an SCP program directly in C#, I know the source
code for Putty is available (it's in C), but I'm not sure I'd know where to
start with it! Maybe if I find myself with a lot of extra time on my hands
I'll try and figure it out. Unfortunately, they don't have it available as a
DLL. If anybody does know of some (free) SSH utility classes that I can use
in my app I'd certainly be grateful. I tried searching online, but didn't
find anything.
 
J

Jon Skeet [C# MVP]

Matt Burland said:
Thanks for your help. I was starting to think it might be a problem with
pscp itself rather than anything I'm doing. I was also thinking it might be
something to do with how the Process class works. I know from the MSDN docs
that if you redirect the stdout and don't read it, then it can fill the pipe
up and hang the process. I was wondering if there isn't a minimum amount of
data that needs to be written to the pipe before it'll let you read anything
at all from the parent process?

I don't think so.
Something like the data is only transferred
to the parent process in blocks of some minimum size to avoid slowing both
processes down?

I think it's just a case of whether or not the other process has
flushed its output, although I could be wrong.
Along the lines of writing an SCP program directly in C#, I know the source
code for Putty is available (it's in C), but I'm not sure I'd know where to
start with it! Maybe if I find myself with a lot of extra time on my hands
I'll try and figure it out. Unfortunately, they don't have it available as a
DLL. If anybody does know of some (free) SSH utility classes that I can use
in my app I'd certainly be grateful. I tried searching online, but didn't
find anything.

I believe SSH involves quite a lot of state - making bits of Putty/pscp
etc available as a DLL would involve quite a lot of P/Invoking from C#.
If I get some free time in the near future, I might consider looking at
writing a library though - nothing very soon though, I'm afraid.

In the mean time, I suggest you email the Putty bugs/wishlist address
to ask about the flushing business - it could be fairly easy to fix.
 
M

Matt Burland

Along the lines of writing an SCP program directly in C#, I know the
source
I believe SSH involves quite a lot of state - making bits of Putty/pscp
etc available as a DLL would involve quite a lot of P/Invoking from C#.
If I get some free time in the near future, I might consider looking at
writing a library though - nothing very soon though, I'm afraid.

Let me know if you do write a library. I'd certainly be very interested.
In the mean time, I suggest you email the Putty bugs/wishlist address
to ask about the flushing business - it could be fairly easy to fix.
That sounds like a great idea, I think I'll do that.

Thanks again for your help.
 
J

Jekke, Just Jekke

ewww, hungarian notation...

That's not even a variant of Hungarian notation. Hungarian notation
would be:

public string mstrProcessArgs;
public string mstrProcessApp;
public string mstrPassword;
 
M

Matt Burland

That sounds like a great idea, I think I'll do that.

Thanks again for your help.

Actually, I just fixed it myself!! It really was an easy fix in the end
(only one line added!), it just took me quite a while to figure out how to
recompile the whole thing, but once I remembered that there is a VS command
prompt in the VS tools folder it was easy to recompile with the makefile.
Works like a charm now. I quite impressed with myself!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top