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).