Redirecting standard input and output confusion in .Net

Discussion of chess software programming and technical issues.

Moderator: Ras

Karlo Bala
Posts: 373
Joined: Wed Mar 22, 2006 10:17 am
Location: Novi Sad, Serbia
Full name: Karlo Balla

Redirecting standard input and output confusion in .Net

Post by Karlo Bala »

As I know, standard way to redirect standard input and output in C is to create pipes and then pass to a new process through the STARTUPINFO.

Now I found several ways on the net how to do it in .Net. What is the main difference? Thanks.

1.

Code: Select all

         Process myProcess = new Process();
         myProcess.StartInfo.FileName = "Sort.exe"; 
         myProcess.StartInfo.UseShellExecute = false;
         myProcess.StartInfo.RedirectStandardInput = true;
         myProcess.Start();
         StreamWriter myStreamWriter = myProcess.StandardInput;
         myStreamWriter.WriteLine("some text...");
...

2.

Code: Select all

        Process^ pipeClient = gcnew Process();
        pipeClient->StartInfo->FileName = "pipeClient.exe";
        AnonymousPipeServerStream^ pipeServer =
            gcnew AnonymousPipeServerStream(PipeDirection::Out,
            HandleInheritability::Inheritable);
        // Show that anonymous pipes do not support Message mode. 
        try
        {
            Console::WriteLine("[SERVER] Setting ReadMode to \"Message\".");
            pipeServer->ReadMode = PipeTransmissionMode::Message;
        }
        catch (NotSupportedException^ e)
        {
            Console::WriteLine("[SERVER] Exception:\n    {0}", e->Message);
        }

        Console::WriteLine("[SERVER] Current TransmissionMode: {0}.", pipeServer->TransmissionMode);

        // Pass the client process a handle to the server.
        pipeClient->StartInfo->Arguments = pipeServer->GetClientHandleAsString();
        pipeClient->StartInfo->UseShellExecute = false;
        pipeClient->Start();

        pipeServer->DisposeLocalCopyOfClientHandle();

        try
        {
            // Read user input and send that to the client process.
            StreamWriter^ sw = gcnew StreamWriter(pipeServer);

            sw->AutoFlush = true;
            // Send a 'sync message' and wait for client to receive it.
            sw->WriteLine("SYNC");
            pipeServer->WaitForPipeDrain();
            // Send the console input to the client process.
            Console::Write("[SERVER] Enter text: ");
            sw->WriteLine(Console::ReadLine());
            sw->Close();
        }
Best Regards,
Karlo Balla Jr.
User avatar
emadsen
Posts: 441
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: Redirecting standard input and output confusion in .Net

Post by emadsen »

I'm not sure I understand your question. Difference between what and what?

Here's some code I've used in the past to run a hidden console program in the background and monitor its standard output stream. This can be useful when writing a utility program that does some work with the assistance of another console program.

Code: Select all

private static void RunScript()
{
	Process objProcess = null;
	try
	{
		// Start process.
		objProcess = new Process();
		objProcess.StartInfo.FileName = mstrDeployScript;
		objProcess.StartInfo.RedirectStandardOutput = true;
		// Must set shell execute to false in order to read standard output stream.
		objProcess.StartInfo.UseShellExecute = false;
		objProcess.StartInfo.CreateNoWindow = true;
		objProcess.Start();
		while (!objProcess.StandardOutput.EndOfStream)
		{
			string strLine = objProcess.StandardOutput.ReadLine();
			if (strLine.IndexOf("echo error", StringComparison.CurrentCultureIgnoreCase) > -1)
			{
				// Error occurred.
				throw new Exception("ECHO Error");
			}
			strLine = strLine.TrimEnd(Environment.NewLine.ToCharArray());
			WriteMessage(strLine, true);
		}
	}
	finally
	{
		if (objProcess != null)
		{
			if (!objProcess.HasExited)
			{
				objProcess.Kill();
			}
			objProcess.Dispose();
		}
	}
}

Erik Madsen | My C# chess engine: https://www.madchess.net
Karlo Bala
Posts: 373
Joined: Wed Mar 22, 2006 10:17 am
Location: Novi Sad, Serbia
Full name: Karlo Balla

Re: Redirecting standard input and output confusion in .Net

Post by Karlo Bala »

Thank you for answering on my confusing question.

Your solution is to simply write to process input or to read from process output through the StreamWriter and StreamReader. That is one way to do. A second way would be more like in native C/C++ applications, through anonymous pipes. Create pipes and pass them to the new process. Now, I'm interested if there is any substantial difference? Is there any hidden condition, like pipe size, etc.?
emadsen wrote:I'm not sure I understand your question. Difference between what and what?

Here's some code I've used in the past to run a hidden console program in the background and monitor its standard output stream. This can be useful when writing a utility program that does some work with the assistance of another console program.

Code: Select all

private static void RunScript()
{
	Process objProcess = null;
	try
	{
		// Start process.
		objProcess = new Process();
		objProcess.StartInfo.FileName = mstrDeployScript;
		objProcess.StartInfo.RedirectStandardOutput = true;
		// Must set shell execute to false in order to read standard output stream.
		objProcess.StartInfo.UseShellExecute = false;
		objProcess.StartInfo.CreateNoWindow = true;
		objProcess.Start();
		while (!objProcess.StandardOutput.EndOfStream)
		{
			string strLine = objProcess.StandardOutput.ReadLine();
			if (strLine.IndexOf("echo error", StringComparison.CurrentCultureIgnoreCase) > -1)
			{
				// Error occurred.
				throw new Exception("ECHO Error");
			}
			strLine = strLine.TrimEnd(Environment.NewLine.ToCharArray());
			WriteMessage(strLine, true);
		}
	}
	finally
	{
		if (objProcess != null)
		{
			if (!objProcess.HasExited)
			{
				objProcess.Kill();
			}
			objProcess.Dispose();
		}
	}
}

Best Regards,
Karlo Balla Jr.
User avatar
emadsen
Posts: 441
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: Redirecting standard input and output confusion in .Net

Post by emadsen »

Your question is how to "redirect standard input and output" in .NET. Standard input and output is a specialized case of inter-process communication. For this specialized case, the recommended solution in .NET is to use a StreamReader on StandardInput and a StreamWriter on StandardOutput.

OK, let's consider the more general question of how to communicate between processes using .NET.

Pipes are available in .NET, and I believe they're used for inter-process communication on a single machine or between machines. I admit I don't know much about them. I've never used pipes. See this article for details:

Pipe Operations in the .NET Framework

The recommend solution in .NET for inter-process communication is to use Windows Communication Foundation (WCF). WCF supports binary or XML message formats and uni-directional or bi-directional channels. See this article for details:

Windows Communication Foundation

I won't attempt to talk you out of using pipes (because I have no experience with them). My impression is they were added in .NET 3.5 to support advanced scenarios. The more common approach is to use WCF.
Erik Madsen | My C# chess engine: https://www.madchess.net
Daniel Shawul
Posts: 4186
Joined: Tue Mar 14, 2006 11:34 am
Location: Ethiopia

Re: Redirecting standard input and output confusion in .Net

Post by Daniel Shawul »

Karlo, this is not an answer to your question but I like how java/c# hide all the details behind inter-process communication. Programming a GUI becomes so much more enjoyable with that. My code for connecting to an engine, remote shell, database of positions, ics server etc all do their own stuff and then redirect their ios later. So you shouldn't be writing anything like that in C unless you absolutely have to :)

Code: Select all

output = new PrintWriter(proc.getOutputStream(),true);
input = new BufferedReader(
	   new InputStreamReader(proc.getInputStream()));