Guest User

PipeClient.cs

a guest
Dec 12th, 2012
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.52 KB | None | 0 0
  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using Microsoft.Win32.SafeHandles;
  6.  
  7. namespace wyDay.Controls
  8. {
  9.     /// <summary>Allow pipe communication between a server and a client.</summary>
  10.     public class PipeClient : IDisposable
  11.     {
  12.         private object _lock = new object();
  13.  
  14.         [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
  15.         static extern SafeFileHandle CreateFile(
  16.             string pipeName,
  17.             uint dwDesiredAccess,
  18.             uint dwShareMode,
  19.             IntPtr lpSecurityAttributes,
  20.             uint dwCreationDisposition,
  21.             uint dwFlagsAndAttributes,
  22.             IntPtr hTemplate);
  23.  
  24.         /// <summary>Handles messages received from a server pipe</summary>
  25.         /// <param name="message">The byte message received</param>
  26.         public delegate void MessageReceivedHandler(byte[] message);
  27.  
  28.         /// <summary>Event is called whenever a message is received from the server pipe</summary>
  29.         public event MessageReceivedHandler MessageReceived;
  30.  
  31.         /// <summary>Handles server disconnected messages</summary>
  32.         public delegate void ServerDisconnectedHandler();
  33.  
  34.         /// <summary>Event is called when the server pipe is severed.</summary>
  35.         public event ServerDisconnectedHandler ServerDisconnected;
  36.  
  37.         const int BUFFER_SIZE = 4096;
  38.  
  39.         FileStream stream;
  40.         SafeFileHandle handle;
  41.         Thread readThread;
  42.  
  43.         /// <summary>Gets if this client connected to a server pipe.</summary>
  44.         public bool Connected { get; private set; }
  45.  
  46.         /// <summary>The pipe this client is connected to.</summary>
  47.         public string PipeName { get; private set; }
  48.  
  49.         #region Dispose
  50.  
  51.         /// <summary>Indicates whether this instance is disposed.</summary>
  52.         bool isDisposed;
  53.  
  54.         /// <summary>
  55.         /// Finalizes an instance of the <see cref="PipeClient"/> class.
  56.         /// Releases unmanaged resources and performs other cleanup operations before the
  57.         /// <see cref="PipeClient"/> is reclaimed by garbage collection.
  58.         /// </summary>
  59.         ~PipeClient()
  60.         {
  61.             Dispose(false);
  62.         }
  63.  
  64.         /// <summary>Releases unmanaged and - optionally - managed resources.</summary>
  65.         /// <param name="isManaged">Result: <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  66.         protected virtual void Dispose(bool isManaged)
  67.         {
  68.             if (isManaged)
  69.             {
  70.                 lock (_lock)
  71.                 {
  72.                     if (!isDisposed)
  73.                     {
  74.  
  75.                         // dispose managed resources
  76.                         Disconnect();
  77.  
  78.  
  79.                         // free unmanaged resources
  80.                         // Set large fields to null.
  81.  
  82.                         // Instance is disposed
  83.                         isDisposed = true;
  84.                     }
  85.                 }
  86.             }
  87.             // Instance is disposed
  88.             isDisposed = true;
  89.         }
  90.  
  91.         /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  92.         public void Dispose()
  93.         {
  94.             Dispose(true);
  95.             GC.SuppressFinalize(this);
  96.         }
  97.  
  98.         #endregion
  99.  
  100.         /// <summary>Connects to the server with a pipename.</summary>
  101.         /// <param name="pipename">The name of the pipe to connect to.</param>
  102.         public void Connect(string pipename)
  103.         {
  104.             lock (_lock)
  105.             {
  106.                 if (isDisposed) return;
  107.                 if (Connected)
  108.                     throw new Exception("Already connected to pipe server.");
  109.  
  110.                 PipeName = pipename;
  111.  
  112.                 handle =
  113.                     CreateFile(
  114.                         PipeName,
  115.                         0xC0000000, // GENERIC_READ | GENERIC_WRITE = 0x80000000 | 0x40000000
  116.                         0,
  117.                         IntPtr.Zero,
  118.                         3, // OPEN_EXISTING
  119.                         0x40000000, // FILE_FLAG_OVERLAPPED
  120.                         IntPtr.Zero);
  121.  
  122.                 // could not create handle - server probably not running
  123.                 if (handle.IsInvalid)
  124.                 {
  125.                     handle = null;
  126.                     return;
  127.                 }
  128.  
  129.                 Connected = true;
  130.  
  131.                 // start listening for messages
  132.                 readThread = new Thread(Read) { IsBackground = true };
  133.                 readThread.Start();
  134.             }
  135.         }
  136.  
  137.         /// <summary>Disconnects from the server.</summary>
  138.         public void Disconnect()
  139.         {
  140.             lock (_lock)
  141.             {
  142.                 if (isDisposed) return;
  143.  
  144.                 if (!Connected)
  145.                     return;
  146.  
  147.                 // we're no longer connected to the server
  148.                 Connected = false;
  149.                 PipeName = null;
  150.  
  151.                 // clean up resources
  152.                 if (stream != null)
  153.                     stream.Dispose();
  154.  
  155.                 // If Connected == true then handle is non-null.
  156.                 // Thus, just dispose it.
  157.                 handle.Dispose();
  158.  
  159.                 stream = null;
  160.                 handle = null;
  161.             }
  162.         }
  163.  
  164.         void Read()
  165.         {
  166.             lock (_lock)
  167.             {
  168.                 if (isDisposed) return;
  169.  
  170.                 stream = new FileStream(handle, FileAccess.ReadWrite, BUFFER_SIZE, true);
  171.  
  172.             }
  173.  
  174.             byte[] readBuffer = new byte[BUFFER_SIZE];
  175.  
  176.             while (true)
  177.             {
  178.                 int bytesRead = 0;
  179.  
  180.                 using (MemoryStream ms = new MemoryStream())
  181.                 {
  182.                     try
  183.                     {
  184.                         // read the total stream length
  185.                         int totalSize = stream.Read(readBuffer, 0, 4);
  186.  
  187.                         // client has disconnected
  188.                         if (totalSize == 0)
  189.                             break;
  190.  
  191.                         totalSize = BitConverter.ToInt32(readBuffer, 0);
  192.  
  193.                         do
  194.                         {
  195.                             int numBytes = stream.Read(readBuffer, 0, Math.Min(totalSize - bytesRead, BUFFER_SIZE));
  196.  
  197.                             ms.Write(readBuffer, 0, numBytes);
  198.  
  199.                             bytesRead += numBytes;
  200.  
  201.                         } while (bytesRead < totalSize);
  202.                     }
  203.                     catch
  204.                     {
  205.                         //read error has occurred
  206.                         break;
  207.                     }
  208.  
  209.                     //client has disconnected
  210.                     if (bytesRead == 0)
  211.                         break;
  212.  
  213.                     lock (_lock)
  214.                     {
  215.                         if (isDisposed) return;
  216.  
  217.                         //fire message received event
  218.                         if (MessageReceived != null)
  219.                             MessageReceived(ms.ToArray());
  220.                     }
  221.                 }
  222.             }
  223.  
  224.             lock (_lock)
  225.             {
  226.                 if (isDisposed) return;
  227.  
  228.                 // if connected, then the disconnection was
  229.                 // caused by a server terminating, otherwise it was from
  230.                 // a call to Disconnect()
  231.                 if (Connected)
  232.                 {
  233.                     //clean up resource
  234.                     stream.Dispose();
  235.                     handle.Dispose();
  236.  
  237.                     stream = null;
  238.                     handle = null;
  239.  
  240.                     // we're no longer connected to the server
  241.                     Connected = false;
  242.                     PipeName = null;
  243.  
  244.                     if (ServerDisconnected != null)
  245.                         ServerDisconnected();
  246.                 }
  247.             }
  248.         }
  249.  
  250.         /// <summary>Sends a message to the server.</summary>
  251.         /// <param name="message">The message to send.</param>
  252.         /// <returns>True if the message is sent successfully - false otherwise.</returns>
  253.         public bool SendMessage(byte[] message)
  254.         {
  255.             lock (_lock)
  256.             {
  257.                 if (isDisposed) return false;
  258.  
  259.                 if (stream == null) return false;
  260.  
  261.                 try
  262.                 {
  263.                     // write the entire stream length
  264.                     stream.Write(BitConverter.GetBytes(message.Length), 0, 4);
  265.  
  266.                     stream.Write(message, 0, message.Length);
  267.                     stream.Flush();
  268.                     return true;
  269.                 }
  270.                 catch
  271.                 {
  272.                     return false;
  273.                 }
  274.             }
  275.         }
  276.     }
  277. }
Advertisement
Add Comment
Please, Sign In to add comment