Duforu

I am currently tasked with providing a friendlier user interface here at work that will provided new features, but also will interact with several console apps. I need to be able to read/write to these applications. The key is being able to read and write multiple times to the same process.

I understand that I could use batch files for this but this will not provide the real-time feedback and interaction that I need to pull this off cleanly.

I am a former VB6 developer that has been using C# for a short time now. I have written similar applications to this one in VB6 using a DLL written by Franky Braem (http://www.codeproject.com/atl/redirect.asp). This worked great and is what I need to recreate in C#.

I have a code that is capable of reading and writing to the console using the System.Diagnostic namespace redirecting stdin, stdout and stderr (single thread). My issue with this code is that I have to close the StreamWriter of the process in order to read the stdout. Due to this when I attempt to send a subsequent string to the console I get an error that the TextWriter has been closed. Can I reopen this I cannot locate anything on doing this.

I played with a second example written by Scott Hanselman (http://www.hanselman.com/blog/SoManyMistakesForMeToMakeSoLittleTimecapturingStandardErrorAndStandardOutput.aspx) that is multithreaded. This appeared to work but I couldn¡¯t update my Forms controls due to the event I am monitoring was fired by a different thread than the one that created the Textbox control.

So I am at a cross-road here. If there is no way to accomplish this task inside a single threaded application then I need to know how to write to the Textbox control from a different thread.

Any help here will be greatly appreciated!

Thanks



Re: Visual C# General Console app wrapper class(es)

Peter Ritchie

You need to use Control.InvokeRequired and Control.Invoke to get the main GUI thread to invoke the code on the correct thread to avoid cross-thread exceptions. You can do that with anonymous methods or you can create a method and use Invoke with a delegate to that method. If you post some sample code you wish to be executed on the GUI thread I can show you how to do it in both cases.






Re: Visual C# General Console app wrapper class(es)

Duforu

Thanks Peter. I was just getting ready to post that I now have cross-thread working. I did fail to mention that this is .NET 2.0 in my prior post. I found that I had to use Control.BeginInvoke instead of Control.Invoke.

Code Snippet

private void SetConsoleText(string text) {

// InvokeRequired required compares the thread ID of the

// calling thread to the thread ID of the creating thread.

// If these threads are different, it returns true.

if (txtThreadedConsole.InvokeRequired) {

SetTextCallback d = new SetTextCallback(SetConsoleText);

// .NET 2.0 required BeginInvoke instead of Invoke

txtThreadedConsole.BeginInvoke(d, new object[] { text });

} else {

txtThreadedConsole.Text = text;

}

}

I am still having difficulties with keeping the process stdin open for writing. I can only send 1 command and then have to close the stream. Below is code from the class.

Code Snippet

public int Write(ref Process process, string cmd) {

try {

Init();

RunProcess = process;

_stdIn = cmd;

WriteStandardInput();

if (RunProcess.StartInfo.RedirectStandardOutput) {

StandardOutputReader = new Thread(new ThreadStart(ReadStandardOutput));

StandardOutputReader.Start();

}

if (StdInWriter != null) {

StdInWriter.Join();

}

if (StandardOutputReader != null)

StandardOutputReader.Join();

} catch (Win32Exception ex) {

_StandardError = ex.Message.ToString();

}

return 1;

}

private void WriteStandardInput() {

if (RunProcess != null) {

try {

RunProcess.StandardInput.WriteLine(_stdIn);

RunProcess.StandardInput.Close();

} catch (Exception ex) { }

}

}

Any ideas




Re: Visual C# General Console app wrapper class(es)

Peca55

First idea to come in my mind - why you don't use named pipes






Re: Visual C# General Console app wrapper class(es)

Duforu

Hi Peca I guess I don't quite understand your statement above. Are you saying that I should use named pipes If so maybe you could point me in a general direction.

Thanks





Re: Visual C# General Console app wrapper class(es)

Peca55

Yes, you are in the right track - named pipes is a way to go. Course depends, if you use Vista and transacted file system, apartment threading... etc. If I remenber correct, your problem has been solved last year or so. Forum may be differed, but anyway - it has C++ solution and maybe C# and at last, but not the least, it can be categorisied with WEB context. You must hunt oldies! Good luck.

Peca






Re: Visual C# General Console app wrapper class(es)

Arnshea Clayton

You'll want to handle reading from stdout and writing to stdin in separate threads - you'll need to coordinate them. I don't see why you need to close stdin; perhaps a Flush() is needed to send the command

Also, be careful of deadlocks; if the console program writes a lot of data to stdout it may require multiple reads for you to get it all. Until you read it all it won't act on any more input from stdin. The Process class documentation has more information that may be helpful.






Re: Visual C# General Console app wrapper class(es)

Duforu

Arnshea:

Thanks for the response. Now that you mention it in all my frustration I didn't try a flush of stdin() although I have not been successful at getting stdout to produce anything until I close stdin.





Re: Visual C# General Console app wrapper class(es)

Arnshea Clayton

It looks like you'll need some sort of protocol between the caller and the console apps so that you know when to stop reading and when to start writing. You can't use ReadToEnd() unless the console app closes stdout after it's done (not usually the case unless it's exiting...).

Otherwise, you won't know how frequently to ReadLine() from the console app's StandardOut. If the console app has a standard termination sequence (like 2 empty lines or a . or a prompt that gets displayed after every command) you may be able to use that - keep ReadLine()-ing until you see the terminator then either send more commands or close the app.

If you're in a pinch you might be able to use timing - read from standard out after sending the initial response then if the next read blocks for more than X seconds (or minutes or whatever) assume it's safe to try to send more commands. This won't work if the console app has widely variable response time....