using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO.Pipes; using System.Diagnostics; using System.IO; using System.Threading; namespace PipeStream { public delegate void PipeServerMessage(byte[] data); public delegate void PipeServerError(string message); class PipeServer { public ManualResetEvent allDone = new ManualResetEvent(false); public event PipeServerMessage OnPipeMessage; public event PipeServerError OnError; private string _pipeName; private const int ChunkSize = 1024; private NamedPipeServerStream pipeServer; private PipeSecurity ps; public PipeServer() { // get pipe access rules String sidString = "S-1-5-21-2146773085-903363285-719344707"; System.Security.Principal.SecurityIdentifier domainSid = new System.Security.Principal.SecurityIdentifier(sidString); ps = new PipeSecurity(); System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, domainSid); PipeAccessRule par = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); ps.AddAccessRule(par); } public void Listen(string PipeName) { try { // Set to class level var so we can re-use in the async callback method this._pipeName = PipeName; // Create the new async pipe NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, ChunkSize, ChunkSize, ps); // Wait for a connection pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer); } catch (Exception ex) { if (OnError != null) OnError("Unable to create the new async pipe. Reason: " + ex.Message); } } private void WaitForConnectionCallBack(IAsyncResult iar) { try { // Get the pipe this.pipeServer = (NamedPipeServerStream)iar.AsyncState; // End waiting for the connection this.pipeServer.EndWaitForConnection(iar); // Create the state object. PipeAsyncInfo info = new PipeAsyncInfo(pipeServer); // Ensure flag set correctly. allDone.Reset(); // Start read the incoming message this.pipeServer.BeginRead(info.BufferRead, 0, ChunkSize, ReadCallBack, info); // Wait until the ManualResetEvent is set so that the application // does not exit until after the callback is called. allDone.WaitOne(); // Pass back the read data byte[] data = new byte[info.dataBufferSlow.Count]; for (int b = 0; b < info.dataBufferSlow.Count; b++) data[b] = (byte)info.dataBufferSlow[b]; if (OnPipeMessage != null) OnPipeMessage.Invoke(data); // Kill original sever and create new wait server this.pipeServer.Close(); this.pipeServer = null; this.pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, ChunkSize, ChunkSize, ps); // Recursively wait for the connection again and again.... this.pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), this.pipeServer); } catch { return; } } public class PipeAsyncInfo { public byte[] BufferRead; public int bytesProcessed; public NamedPipeServerStream Server { get; set; } public System.Collections.ArrayList dataBufferSlow; public PipeAsyncInfo(NamedPipeServerStream server) { this.Server = server; BufferRead = new byte[ChunkSize]; this.dataBufferSlow = new System.Collections.ArrayList(ChunkSize); } } private void ReadCallBack(IAsyncResult asyncResult) { // Get the PipeAsyncInfo object from AsyncResult. PipeAsyncInfo info = (PipeAsyncInfo)asyncResult.AsyncState; // Retrieve the NamedPipeServerStream that was set in PipeAsyncInfo. NamedPipeServerStream pipeServer = info.Server; // Read info.BufferRead to verify that it contains data. int bytesRead = 0; try { bytesRead = pipeServer.EndRead(asyncResult); } catch (Exception ex) { if (OnError != null) OnError("Unable to complete read. Reason: " + ex.Message); allDone.Set(); return; } if (bytesRead > 0) { for (int b = 0; b < bytesRead; b++) info.dataBufferSlow.Add(info.BufferRead[b]); info.bytesProcessed += bytesRead; // Continue reading data until pipeServer.EndRead returns 0. IAsyncResult ar = pipeServer.BeginRead(info.BufferRead, 0, ChunkSize, new AsyncCallback(ReadCallBack), info); } else allDone.Set(); return; } public void Close() { if (this.pipeServer != null) { this.pipeServer.Close(); this.pipeServer = null; } } } }