6

First of all, I've read all related topics and they gave general idea but implementation doesn't work for me:
Send strings from one console application to another
How to send input to the console as if the user is typing?
Sending input/getting output from a console application (C#/WinForms)
I have a console application that is doing some actions in background until cancellation is requested. Typical usage scenario is :
1) Execute application
2) Enter input data
3) Issue start command
4) After some time passes, enter stop command
5) Exit application
Child application Program.cs :

static void Main()
{
    Console.WriteLine("Enter input parameter : ");
    var inputParameter = Console.ReadLine();
    Console.WriteLine("Entered : " + inputParameter);

    var tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;
    Task.Factory.StartNew(() =>
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Stopping actions");
                    return;
                }
                // Simulating some actions
                Console.Write("*");
            }
        }, token);
    if (Console.ReadKey().KeyChar == 'c')
    {
        tokenSource.Cancel();
        Console.WriteLine("Stop command");
    }
    Console.WriteLine("Finished");
    Console.ReadLine();
}

What I'm looking for is some sort of host utility to control this application - spawn multiple instances and perform required user actions on each instance. Host application Program.cs :

static void Main()
{
    const string exe = "Child.exe";
    var exePath = System.IO.Path.GetFullPath(exe);
    var startInfo = new ProcessStartInfo(exePath)
    {
        RedirectStandardOutput = true,
        RedirectStandardInput = true,
        WindowStyle = ProcessWindowStyle.Hidden,
        WindowStyle = ProcessWindowStyle.Maximized,
        CreateNoWindow = true,
        UseShellExecute = false
    };

    var childProcess = new Process { StartInfo = startInfo };
    childProcess.OutputDataReceived += readProcess_OutputDataReceived;
    childProcess.Start();
    childProcess.BeginOutputReadLine();
    Console.WriteLine("Waiting 5s for child process to start...");
    Thread.Sleep(5000);

    Console.WriteLine("Enter input");
    var msg = Console.ReadLine();
    // Sending input parameter
    childProcess.StandardInput.WriteLine(msg);
    // Sending start command aka any key
    childProcess.StandardInput.Write("s");
    // Wait 5s while child application is working
    Thread.Sleep(5000);
    // Issue stop command
    childProcess.StandardInput.Write("c");
    // Wait for child application to stop
    Thread.Sleep(20000);
    childProcess.WaitForExit();
    Console.WriteLine("Batch finished");    
    Console.ReadLine();
}

When I run this tool, after first input it crashes with "has stopped working" error and prompt to send memory dump to Microsoft. Output window in VS shows no exceptions.
Guess this problem occurs somewhere between applications and may be because of output stream buffer overflow (child app is writing a lot of stars each second which mimics real output which may be huge) and I yet have no idea how to fix it. I don't really need to pass child's output to host (only send start-stop commands to child), but commenting RedirectStandardOutput and OutputDataReceived doesn't fix this problem. Any ideas how to make this work?

Community
  • 1
  • 1
Jaded
  • 1,802
  • 6
  • 25
  • 38
  • Why not using IPC and Pipe? It is very easy if you want to work on a single client or inside a LAN. WCF is another option. – Alireza Sep 11 '13 at 13:27
  • I need to literally pass 3 strings from one application to another. Trying to keep things as simple as possible. – Jaded Sep 11 '13 at 13:29
  • There is in general not much point to starting many processes to get a job done. You'll accomplish the exact same thing by starting many threads. Many advantages, including getting much better diagnostics when something goes wrong. – Hans Passant Sep 11 '13 at 13:31
  • Makes no difference what you want to communicate. Recommended Readings: http://msdn.microsoft.com/en-us/library/bb546085.aspx and http://stackoverflow.com/questions/13806153/example-of-named-pipes – Alireza Sep 11 '13 at 13:32
  • @HansPassant Well, each child application issues around 1000 service requests (20 simultaneous on average) per minute and memory consumption is an issue (OutOfMemory). Not much room for optimization taking into account the fact standard WCF and SoapHttpClientProtocol wrappers are used. – Jaded Sep 11 '13 at 13:42
  • There is very good point to use separate process instead of thread, for example when you want to avoid out of memory exception caused by the large object heap fragmentation in environments where the risk is very real (32bit processes and/or older versions of CLR) – jhexp Mar 17 '14 at 17:25

3 Answers3

10

I would recommend using NamedPipeServerStream and NamedPipeClientStream, which allows you to open a stream which will communicate between processes on a given machine.

First, this will create a pipe server stream and wait for someone to connect to it:

    var stream = new NamedPipeServerStream(this.PipeName, PipeDirection.InOut);
    stream.WaitForConnection();
    return stream;

Then, this will connect to that stream (from your other process), allowing you to read / write in either direction:

    var stream = new NamedPipeClientStream(".", this.PipeName, PipeDirection.InOut);
    stream.Connect(100);
    return stream;
Jon G
  • 4,083
  • 22
  • 27
0

Another alternative is to use MSMQ, you can find a good tutorial here

Andre Lombaard
  • 6,985
  • 13
  • 55
  • 96
0

I would advise to look to the Working with memory mapped files in .NET 4 http://blogs.msdn.com/b/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx

It's fast and efficient.

Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57