2

I have a program, that has to comunicate with another program that is called from the first. I have managed to send the required data from the first to the second program using NamedPipes. When the second program closes, i need to send some data back to the first program. I set up a NamedPipeServerStream in the first program and from the Closing event of the second program a NamedPipeClientStream. Now when i try to write from ClientStream i get a broken pipe error.

This is the code from the first program:

private void CreateOverlay(object sender, EventArgs e)
    {
        if (oinstallfolder != null)
        {
            string processfilename = oinstallfolder.ToString() + "\\SecondProgram.exe";*/

        string processfilename = "SecondProgram.exe";

        if (File.Exists(processfilename))
            {

                foreach (Process clsProcess in Process.GetProcesses())
                {
                    if (clsProcess.ProcessName.Equals("SecondProgram"))
                    {
                        this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
                        this.threadHandleOverlayBounds.Start();
                        this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
                        this.threadHandleOverlayFile.Start();
                        ShowWindow(clsProcess.MainWindowHandle, SW_SHOWNORMAL);
                        SetForegroundWindow(clsProcess.MainWindowHandle);
                        return;
                    }
                }
            try
            {
                this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
                this.threadHandleOverlayBounds.Start();
                Logger.Logger.Write("Log.txt", "Starting Filethread serverside");

                this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
                this.threadHandleOverlayFile.Start();

                Process.Start(processfilename);
            }
            catch { }

            }
        }
    }


 private void ExchangeMapOverlayFileServer()
        {
            try
            {
                using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("OverlayFilePipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
                {
                    string line;
                    namedPipeServer.WaitForConnection();
                    StreamReader sr = new StreamReader(namedPipeServer);
                    line = sr.ReadLine();
                    namedPipeServer.Disconnect();
                    namedPipeServer.Close();
                }
            }
            catch(Exception e)
            {
                Logger.Logger.Write("OverlayGenerator.txt", "namedPipeServer exception: " + e.Message + "\n" + e.StackTrace);
            }

        }

this is the code from the second program

this.Closing += (s, a) =>
        {
            Logger.Logger.Write("Log.txt", "Window Closing");
            this.threadHandleOverlayFile = new Thread(new ThreadStart(this.HandleWindowClosing));
            this.threadHandleOverlayFile.Start();
            while (!done)
            {
                Thread.Sleep(100);
            }

        };


  private void HandleWindowClosing()
    {
        if (!String.IsNullOrEmpty(this.latestSavedOverlayPath))
        {
            try
            {
                using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "OverlayFilePipe", PipeDirection.Out))
                {
                    namedPipeClient.Connect();
                    StreamWriter sw = new StreamWriter(namedPipeClient);
                    sw.AutoFlush = true;
                    sw.WriteLine("testphrase");
                    namedPipeClient.Close();
                    this.done = true;
                }

            }
            catch (Exception e) { Logger.Logger.Write("OverlayGenerator.txt", "Exception in Client: " + e.Message + "\n" + e.StackTrace); }
        }
        else
        {
            Logger.Logger.Write("OverlayGenerator.txt", "Latest saved OverlayPath = " + this.latestSavedOverlayPath);
        }
    }

I tried this with Autoflush=true and without. With it, i get a broken pipe exception at the line

sw.WriteLine("testphrase");

and without it, the client side just runs to the end and nothing happens at all.

Where is my mistake? Thank you.

EDIT

OK, i just don't get it. I made a test program, that is build the same way as the actual one. Two applications, the first starting the second. I start the pipe server in a thread in the first application and the client, also in a thread, in the second. The only difference is, that i run this test project in debug mode, which i can't do for the actual program. Now, in the test program, this matter is realy simple and it works. When i use the exact same approach in the actual program, it doesn't work. In the testprogram i need to use flush on the streamwriter and i don't get an exception. The syncronization of the threads gets handled by the pipe itself, as it should be if i understood this correctly.

The Master looks like this:

private const string CLIENTPROC = "C:\\Users\\Maik\\Source\\Repos\\PipeTest\\PipeClient\\obj\\x86\\Release\\PipeClient.exe";
        private ManualResetEvent threadResetEvent;
        private Thread threadHandlePipeSendLast;
        private Process procClient;
        private string msgPipeSend;
        private volatile bool bMsgPipeSend;
        public MainWindow()
        {
            InitializeComponent();
            this.threadResetEvent = new ManualResetEvent(false);
            System.Diagnostics.Debug.WriteLine("### starting thread");
            this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
            this.threadHandlePipeSendLast.Start();
        }

        private void ExchangeMapOverlayFileServer()
        {
            System.Diagnostics.Debug.WriteLine("server thread started");
            Thread.CurrentThread.Name = "apocalypse";
            try
            {
                using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("ClosingPipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
                {
                    string line;

                    namedPipeServer.WaitForConnection();
                    StreamReader sr = new StreamReader(namedPipeServer);
                    Thread.Sleep(100);
                    line = sr.ReadLine();
                    handleRecvMsgFromPipe(line);
                    namedPipeServer.Disconnect();
                    namedPipeServer.Close();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("### " + e.Message + "\n" + e.StackTrace);
            }
        }

        private void handleRecvMsgFromPipe(string line)
        {
            this.outbox.Text = line;
        }

        private void buttonOpenFormClient_Click(object sender, EventArgs e)
        {
#if DEBUG

#else
            if (this.procClient == null)
            {
                try
                {
                    this.procClient = Process.Start(new ProcessStartInfo(CLIENTPROC));
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.Message, "Error");
                }
            }
#endif
        }
    }

And that's the client side:

private ManualResetEvent threadResetEvent;
        private Thread threadHandlePipeSendLast;

        private string msgPipeSend;
        private volatile bool bMsgPipeSend;
        private bool done;

        public MainWindow()
        {
            InitializeComponent();
            this.threadResetEvent = new ManualResetEvent(false);
            this.Closing += (s, a) =>
            {
                System.Diagnostics.Debug.WriteLine("+++ FormClosing started.");
                this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.HandleWindowClosing));
                this.threadHandlePipeSendLast.Start();
                while (!done)
                {
                    Thread.Sleep(1000);
                }
            };
        }

        private void HandleWindowClosing()
        {
            try
            {
                using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "ClosingPipe", PipeDirection.Out))
                {
                    namedPipeClient.Connect();
                    StreamWriter sw = new StreamWriter(namedPipeClient);
                    //sw.AutoFlush = true;
                    sw.WriteLine("last message");
                    namedPipeClient.WaitForPipeDrain();
                    namedPipeClient.Close();
                    this.done = true;
                }

            }
            catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message + "\n" + e.StackTrace); }
        }

Can anyone tell me, why this works in the test app and not in the actual one? I also tried various things from Thread.Sleep(x) at different points in the programs over Thread.Join() to pipe methods like WaitForPipeDrain (which is just ignored).

17
  • Which instruction give exception? You are getting a Closing Exception which is before the connection actually closed. From the exception is looks like you may be flushing a pipe that is closed. If the application is closed why flush? There is no app to write to. Commented Aug 17, 2019 at 12:14
  • sw.WriteLine(this.latestSavedOverlayPath); gives the exception. As far as my intention goes, i want to open the NamedPipeServerStream when program 2 is opened and the NamedPipeClientStream when program 2 is closing. Then i want to connect to the ServerStream and write the string to the pipe and read it at the Serverside. I don't get why the pipe is closed, when i succesfully conect a few lines before and namedPipeClient.IsConnected is true. Commented Aug 17, 2019 at 13:06
  • You are writing as the form is closing which will close the pipe. Commented Aug 17, 2019 at 13:40
  • I understand. So where would i have to write into the pipe? Commented Aug 17, 2019 at 13:50
  • Before the second app closes. The first application is the client( Master) and second application is the server (slave). The slave should never close without the client knowing so the client doesn't try to send after the slave closes. The slave should send a message when completed, the client stops sending, and then sends a message to slave to close. Commented Aug 17, 2019 at 16:09

0

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.