Cosmos/source2/Debug/Cosmos.Debug.Common/PipeServer.cs
EdwardNutting_cp c7a239f1c3 Fixes:
- VS error message when closing VS during a debugging session
 - VS can now do multiple debugging session in a row without needing restart. Issues: 
        - Unhandled exceptions in DataReceived event handler caused UpPipe to break resulting in total loss of connection between AD7Process and ToolsWindows
        - Added new code to clean out the Action handler that PipeServer uses. By holding onto the old Action reference, it was holding onto a reference to the old AD7Process instance thus reulting in all sorts of weird errors.
2014-01-11 16:25:10 +00:00

97 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading;
namespace Cosmos.Debug.Common {
public class PipeServer {
protected bool KillThread = false;
protected NamedPipeServerStream mPipe;
public event Action<byte, byte[]> DataPacketReceived;
protected string mPipeName;
public PipeServer(string aPipeName) {
mPipeName = aPipeName;
}
public void Stop() {
KillThread = true;
if (mPipe.IsConnected) {
mPipe.Close();
} else {
// Kick it out of the WaitForConnection
var xPipe = new NamedPipeClientStream(".", mPipeName, PipeDirection.Out);
xPipe.Connect(100);
}
}
public void CleanHandlers()
{
DataPacketReceived = null;
}
// See comment in ctor as to why we have to make this new ReadByte replacement
protected byte ReadByte() {
byte[] xByte = new byte[1];
if (mPipe.Read(xByte, 0, 1) == 0) {
throw new Exception("Pipe has been closed.");
}
return xByte[0];
}
protected Thread mThread;
public void Start() {
mThread = new Thread(ThreadStartServer);
mThread.Start();
}
protected void ThreadStartServer() {
try {
// Some idiot MS intern must have written the blocking part of pipes. There is no way to
// cancel WaitForConnection, or ReadByte. (pipes introduced in 3.5, I thought one time I read
// that 4.0 added an abort option, but I cannot find it)
// If you set Async as the option, but use sync calls, .Close can kind of kill them.
// It causes exceptions to be raised in WaitForConnection and ReadByte (possibly due to another
// issue with threads and exceptions without handlers, maybe check again later), but they just
// loop over and over on it... READ however with the async option WILL exit with 0....
// Its like VB1 and adding to sorted listboxes over all again... no one dogfooded this stuff.
// And yes we could use async.. but its SOOO much messier and far more complicated than it ever
// should be.
//
// Here is an interesting approach using async and polling... If need be we can go that way:
// http://stackoverflow.com/questions/2700472/how-to-terminate-a-managed-thread-blocked-in-unmanaged-code
while (!KillThread) { // Loop again to allow mult incoming connections between debug sessions
using (mPipe = new NamedPipeServerStream(mPipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous)) {
mPipe.WaitForConnection();
byte xCmd;
int xSize;
while (mPipe.IsConnected && !KillThread) {
xCmd = ReadByte();
xSize = ReadByte() << 8;
xSize = xSize | ReadByte();
byte[] xMsg = new byte[xSize];
mPipe.Read(xMsg, 0, xSize);
if (DataPacketReceived != null)
{
DataPacketReceived(xCmd, xMsg);
}
}
}
}
} catch (Exception ex) {
// Threads MUST have an exception handler
// Otherwise there are side effects when an exception occurs
}
}
}
}