4

I am attempting bidirectional communication (IPC) between 2 C# Apps using only Standard Input streams. The parent app launches the child app with a Process, where RedirectStandardInput = true. So the parent process is able to send commands to the child process using childProc.StandardInput.WriteLine(). I am capturing these messages asynchronously using BeginRead() and EndRead() of the stream acquired with Console.OpenStandardInput(). Parent to child communication is working great. I am able to send and receive messages asynchronously.

But when the child attempts to write to the parent, using the same code, .NET throws this error:

StandardInput has not been redirected.

So, in simple terms, how does a .NET app redirect its own standard input stream? I will then redirect the standard input stream of my parent process, so the child can send messages to it.

My parent process is a WinForms C# App built with .NET 4.0 x86.


Edit: Here is the code of the IPC Server

internal class IPCServer {

    private Stream cmdStream;
    private byte[] cmdBuffer = new byte[4096];

    public IPCServer() {

        cmdStream = Console.OpenStandardInput(4096);

        GetNextCmd();
    }

    private void GetNextCmd() {

        // wait for next
        cmdStream.BeginRead(cmdBuffer, 0, cmdBuffer.Length, CmdRecived, null);
    }

    private void CmdRecived(IAsyncResult ar) {

        // input read asynchronously completed
        int bytesRead = 0;
        try {
            bytesRead = cmdStream.EndRead(ar);
        } catch (Exception) { }
        if (bytesRead > 0) {

            // accept cmd
            .........

            // wait for next
            GetNextCmd();
        }
    }


}

And here is the code of the IPC Client

internal class IPCClient {

    private Process appProc;

    public IPCClient(Process appProcess) {

        if (!appProcess.StartInfo.RedirectStandardInput) {
            //MessageBox.Show("IPCClient : StandardInput for process '" + appProcess.ProcessName + "' has not been 'redirected'!");
            return;
        }

        appProc = appProcess;

    }

    public void SendCmd(string cmd) {

        if (appProc != null) {
            appProc.StandardInput.WriteLine(cmd);
        }

    }

}

In the parent process:

// open child app
ProcessStartInfo info = new ProcessStartInfo(childProcPath, args);
info.WorkingDirectory = childProcDir;
info.LoadUserProfile = true;
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.RedirectStandardInput = true;

childProc = Process.Start(info);

// connect to app for IPC
Client = new IPCClient();
Client.Init(childProc);

// recieve cmds from app
Server = new IPCServer();
Server.OnCmdRecieved = GotCmd;
Server.Init();

In the child process:

ownerProcess = ....

Server = new IPCServer();
Server.OnCmdRecieved = GotCmd;
Server.Init();

Client = new IPCClient();
Client.Init(ownerProcess);
3
  • Show some code instead of describing its principles in words. Commented Dec 3, 2015 at 11:17
  • Use shared memory if feasible Commented Dec 3, 2015 at 11:35
  • I/O redirection is a very ho-hum way to do IPC, having to use text and battling the encoding limitations and giving up on normal console usage is very little fun. Use a named pipe instead. Commented Dec 3, 2015 at 13:45

2 Answers 2

2

You can do it in a more convenient way. Just make your client application know nothing about input \ output redirection. Server should bother about redirection.

I have implemented a simplest client-server application using your technique, which demonstrates how it should be used.

Client

Client is a simplest application, which simply echoes the message back and closes when you enter exit:

static void Main(string[] args)
{
    string str;

    do
    {
        str = Console.ReadLine();

        Console.WriteLine("Executed: " + str);
    } while (str != "exit");
}

The client knows nothing about redirection, it simply works like a console application and reads \ writes into a console.

Server

Server runs client processes and reads \ writes in its streams.

Process p = new Process();

p.StartInfo.FileName = "ConsoleApplication1.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;

p.Start();

p.StandardInput.WriteLine("a");
p.StandardInput.WriteLine("b");
p.StandardInput.WriteLine("c");
p.StandardInput.WriteLine("d");
p.StandardInput.WriteLine("exit");
p.StandardInput.WriteLine("f");

p.StandardInput.Close();

string res = p.StandardOutput.ReadToEnd();

After execution of this code, res contains the following text:

Executed: a
Executed: b
Executed: c
Executed: d
Executed: exit
Sign up to request clarification or add additional context in comments.

1 Comment

Not possible this way, because the client app will be communicating asynchronously with the server. Its not a request/response system.
1

What if the child process simply uses BeginRead() and EndRead() on the child process' StandardOutput stream. That should work!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.