本封装的组件,可以方便连接本机或远程 主机的命名管道。

连接远程主机时,需要提供帐号和密码。

同时解决了委托事件中修改界面元素时引起的安全错误。

代码为【调试】版,有不少调试信息传递到调用者。

using System;
using System.ComponentModel;
using System.IO.Pipes;
using System.Security.Principal;
using System.Threading;
using System.Drawing;

namespace LeesNamedPipeClient
{
    [DefaultProperty("PipeName")]
    [DefaultEvent("OnPipeReadData")]
    [ToolboxBitmap("fifo.ico")]
    public partial class LeesNamedPipeClient : Component
    {

        NamedPipeClientStream _PipeClient = null;

        public LeesNamedPipeClient()
        {
            InitializeComponent();
        }

        public LeesNamedPipeClient(IContainer container)
        {
            container.Add(this);            
            InitializeComponent();
        }

        #region 属性
        [Browsable(true), Category("连接设置"), Description("设置连接的主机"), DefaultValue(".")]
        public string Host { get; set; }

        private bool _isLocalHost;
        [Browsable(true), Category("连接设置"), Description("是否本机"), DefaultValue("true")]
        public bool IsLocalHost
        {
            set
            {                
                _isLocalHost = value;
                if (value)
                {
                    Host = ".";
                }
            }
            get
            {
                return _isLocalHost;
            }
        }


        [Browsable(true), Category("连接设置"), Description("连接到远程主机的帐号,本机连接忽略此项。"), DefaultValue("")]
        public string UserName { get; set; }


        [Browsable(true), Category("连接设置"), Description("连接到远程主机的密码,本机连接忽略此项。"), DefaultValue("")]
        public string PassWord { get; set; }


        [Browsable(true), Category("连接设置"), Description("管道名字"), DefaultValue("PipeName")]
        public string PipeName { get; set; }

        [Browsable(true), Category("连接设置"), Description("超时时间(毫秒)"), DefaultValue(1000)]
        public uint TimeOut { get; set; }


        [Browsable(false)]
        /// <summary>
        /// 获取一个值,该值指示当前流是否支持读操作。
        /// 如果流支持读操作,则为 true;否则为 false。
        /// </summary>
        public bool CanRead { get { return _PipeClient.CanRead; } }

        [Browsable(false)]
        /// <summary>
        /// 获取一个值,该值指示当前管道是否支持写操作。
        /// 如果管道支持写操作,则为 true;否则为 false。
        /// </summary>
        public bool CanWrite { get { return _PipeClient.CanWrite; } }


        [Browsable(false)]
        /// <summary>
        /// 获取一个值,该值指示当前管道是否支持查找操作。
        /// 在所有情况下均为 false。
        /// </summary>
        public bool CanSeek { get { return _PipeClient.CanSeek; } }


        [Browsable(false)]
        /// <summary>
        /// 获取一个值,该值指示当前管道是否已经连接
        /// </summary>
        public bool IsConnected
        {
            get
            {
                if (_PipeClient == null)
                    return false;
                return _PipeClient.IsConnected;
            }
        }

        #endregion

        #region 事件
        /// <summary>
        /// 从管道中读取数据完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void PipeReadDataHandle(object sender, PipeReadDataEventArgs e);
        /// <summary>
        /// 管道写完成/可以进行下一次写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void PipeWriteOverHandle(object sender, EventArgs e);
        public delegate void PipeConnecteHandle(object sender, EventArgs e);
        public delegate void PipeColsedHandle(object sender, EventArgs e);
        public delegate void PipeDisconnectHandle(object sender, EventArgs e);

        public delegate void PipeErrorHandle(object sender, PipeErrorEventArgs e);
        
        [Description("从管道中读取数据完成")]
        /// <summary>
        /// 从管道中读取数据完成
        /// </summary>
        public event PipeReadDataHandle OnPipeReadData=null;




        [Description("管道写完成/可以进行下一次写")]
        /// <summary>
        /// 管道写完成/可以进行下一次写
        /// </summary>
        public event PipeWriteOverHandle OnPipeWriteOver = null;


        [Description("管道已经连接成功")]
        /// <summary>
        /// 管道已经连接成功
        /// </summary>
        public event PipeConnecteHandle OnPipeConnect = null;


        [Description("管道已经连接成功")]
        /// <summary>
        /// 主动关闭管道连接
        /// </summary>
        public event PipeColsedHandle OnPipeClosed = null;


        [Description("管道被动关闭【管道服务器主动关闭连接】")]
        /// <summary>
        /// 管道被动关闭【管道服务器主动关闭连接】
        /// </summary>
        public event PipeDisconnectHandle OnPipeDisconnect = null;


        [Description("有错误发生")]
        public event PipeErrorHandle OnPipeError = null;
        #endregion

        #region 方法
        #region 私有方法

        private IntPtr token = IntPtr.Zero;
        private WindowsIdentity newIdentity;
        private WindowsImpersonationContext impersonatedUser;
        private bool _isLogonSuccessed = false;
        private bool LogonToRemote()
        {
            _isLogonSuccessed = false;
            try
            {
                _isLogonSuccessed = Win32Helper.LogonUser(UserName, Host, PassWord,
                    Win32Helper.LOGON32_LOGON_NEW_CREDENTIALS,
                    Win32Helper.LOGON32_PROVIDER_DEFAULT, ref token);

                newIdentity = new WindowsIdentity(token);
                impersonatedUser = newIdentity.Impersonate();


#if DEBUG

                string sMsg= string.Format("UserName:{0}   Password:{1}    Host:{2}    newIdentity={3},impersonatedUser={4}",
                    UserName, PassWord, Host, newIdentity == null ? "NULL" : "Not Null", impersonatedUser == null ? "NULL" : "Not NULL");
                MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.REMOTELOGON, sMsg));
#endif
            }
            catch (Exception e)
            {
                //OnPipeError?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.REMOTELOGON, e.Message));
                MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.REMOTELOGON, e.Message));
                return false;
            }
            return _isLogonSuccessed;
        }
        private void LogonOut()
        {
            if (_isLogonSuccessed)
            {
                if (impersonatedUser != null)
                    impersonatedUser.Undo();
                if (token != IntPtr.Zero)
                    Win32Helper.CloseHandle(token);
            }
        }

        private void PipeWriteCallback(IAsyncResult ar)
        {
            var pipe = (NamedPipeClientStream)ar.AsyncState;

            pipe.EndWrite(ar);
            pipe.Flush();
            pipe.WaitForPipeDrain();

            MyInvoke(OnPipeWriteOver, this, new EventArgs());
            //OnPipeWriteOver?.Invoke(this, new EventArgs());
            
        }
        private void ReleasePipe()
        {
            if(_PipeClient!=null)
            {
                if(_PipeClient.IsConnected)
                {
                    _PipeClient.Close();
                    _PipeClient = null;
                    MyInvoke(OnPipeClosed, this, new EventArgs());
                }
                else
                {
                    _PipeClient = null;
                    MyInvoke(OnPipeDisconnect, this, new EventArgs());
                }                
            }
            LogonOut();
        }

        private class AsyncReadState
        {
            public NamedPipeClientStream Pipe { get; set; }
            public byte[] Buffer { get; set; }

            public ManualResetEvent EventHandle { get; set; }
        }
        private void ReadThread()
        {
            while (true)
            {
                if (_PipeClient != null)
                {
                    try
                    {
                        if (_PipeClient.IsConnected)
                        {
                            AsyncReadState asyncState = new AsyncReadState()
                            {
                                Pipe = _PipeClient,
                                Buffer = new byte[4096],
                                EventHandle = new ManualResetEvent(false)
                            };

                            MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.READ, "beginread"));
                            _PipeClient.BeginRead(asyncState.Buffer, 0, 4096, ReadCallBack, asyncState);
                            asyncState.EventHandle.WaitOne();
                        }
                        else
                        {
                            break;                         
                        }
                    }
                    catch(ArgumentException e)
                    {
                        //OnPipeError?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        break;
                    }
                    catch (ObjectDisposedException e)//管道已关闭。
                    {
                        //OnPipeDisconnect?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        //OnPipeError?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        break;
                    }
                    catch(InvalidOperationException e)//管道已断开连接,正在等待连接,或尚未设置句柄。
                    {
                        //OnPipeDisconnect?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        MyInvoke(OnPipeDisconnect, this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        break;
                    }
                    catch (Exception e)
                    {
                        //OnPipeError?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.READ, ex.Message));
                        MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.READ, e.Message));
                        break;
                    }
                }
                else
                    break;
            }

            MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.READ, "PipeReadThreadOver"));
            ReleasePipe();

        }

        private void ReadCallBack(IAsyncResult ar)
        {
            var asyncState = (AsyncReadState)ar.AsyncState;

            int nReadLength = asyncState.Pipe.EndRead(ar);
            if (nReadLength == 0)
            {                
                MyInvoke(OnPipeDisconnect, this, new EventArgs());
                ReleasePipe();
            }
            else
            {
                MyInvoke(OnPipeReadData, this, new PipeReadDataEventArgs(asyncState.Buffer, nReadLength));
            }
            asyncState.EventHandle.Set();
        }
        #endregion

        /// <summary>
        /// 根据设置,连接到管道服务器
        /// </summary>
        public void Connect()
        {
            //bool bRet = false;
            if(!IsLocalHost)
            {
                if(string.IsNullOrEmpty(UserName)
                    || string.IsNullOrEmpty(Host)
                    || string.IsNullOrEmpty(PassWord))
                {
                    throw new Exception("远程连接必须设置主机地址、登录帐号、登录密码!");                    
                }                

                if(!LogonToRemote())
                {
                    return;
                }
            }
            else
            {
                if (string.IsNullOrEmpty(Host))
                {
                    Host = ".";
                }
            }
            try
            {
                if (string.IsNullOrEmpty(PipeName))
                {
                    throw new Exception("必须设置管道名称!");
                }
                _PipeClient = new NamedPipeClientStream(Host,
                    PipeName,
                    PipeDirection.InOut,
                    PipeOptions.Asynchronous,
                    System.Security.Principal.TokenImpersonationLevel.Impersonation);

                _PipeClient.Connect((int)TimeOut);
                Thread t = new Thread(new ThreadStart(ReadThread));
                t.Name = "PipeRreadThread";
                t.IsBackground = true;
                t.Start();
                try
                {
                    if (_PipeClient.CanTimeout)
                    {
                        _PipeClient.WriteTimeout = (int)TimeOut;
                        _PipeClient.ReadTimeout = (int)TimeOut;
                    }
                }
                catch(InvalidOperationException)
                { }
                //OnPipeConnect?.Invoke(this, new EventArgs());
                MyInvoke(OnPipeConnect, this, new EventArgs());
            }
            catch(TimeoutException ex)
            {
                throw ex;
            }
            catch(Exception e)
            {
                
                //OnPipeError?.Invoke(this, new PipeErrorEventArgs(PipeErrorReson.CONNECT, e.Message));
                MyInvoke(OnPipeError, this, new PipeErrorEventArgs(PipeErrorReson.CONNECT, e.Message));
                return;
            }

            //return bRet;
        }

        public void Close()
        {
            ReleasePipe();
        }
        /// <summary>
        /// 将字节数组写入管道
        /// </summary>
        /// <param name="data">要写入的字节数组</param>
        public void Write(byte[] data)
        {
            Write(data, 0, data.Length);
        }
        /// <summary>
        /// 将字节数组写入管道
        /// </summary>
        /// <param name="data">要写入的字节数组</param>
        /// <param name="offset">数组起始位置</param>
        /// <param name="count">写入的字节数</param>
        public void Write(byte[] data,int offset,int count)
        {
            if(_PipeClient==null)
            {
                throw new Exception("请在写数据之前连接管道");
            }
            if(!_PipeClient.IsConnected)
            {
                throw new Exception("请在写数据之前连接管道");
            }
            if(!_PipeClient.CanWrite)
            {
                throw new Exception("该管道不支持写操作");
            }
            if(count>4096)
            {
                throw new Exception("要求写入数据总长度不大于4096");
            }
            if(offset<0||offset>data.Length-1||count<0)
            {
                throw new Exception("参数错误");
            }
            if (offset +count > data.Length)
            {
                throw new Exception("参数错误");
            }
            if (count == 0)
            {
                //OnPipeWriteOver?.Invoke(this, new EventArgs());
                MyInvoke(OnPipeWriteOver, this, new EventArgs());
                return;
            }
            _PipeClient.BeginWrite(data, offset, count, PipeWriteCallback, _PipeClient);
        }
        #endregion

        protected virtual void MyInvoke(Delegate del, object sender, object args)
        {
            if (del != null)
            {
                if (del.Target is System.ComponentModel.ISynchronizeInvoke)
                {
                    //当前委托的实例。如一个Form实例
                    System.ComponentModel.ISynchronizeInvoke aSynch = del.Target as System.ComponentModel.ISynchronizeInvoke;
                    if (aSynch.InvokeRequired)
                    {
                        //此类对象绑定到特定线程并不是线程安全。 如果正在从另一个线程调用的方法,则必须使用Invoke封送到正确的线程调用的方法。
                        //如在非UI线程中修改UI控件
                        object[] objs = new object[2] { sender, args };
                        aSynch.BeginInvoke(del, objs);
                    }
                    else
                    {   
                        //不涉及线程安全问题时,直接调用
                        del.DynamicInvoke(sender, args);
                    }
                }
            }
        }
    }

    public enum PipeErrorReson
    {
        /// <summary>
        /// 登录远程主机
        /// </summary>
        REMOTELOGON,
        /// <summary>
        /// 连接到管道服务器
        /// </summary>
        CONNECT,
        /// <summary>
        /// 写数据
        /// </summary>
        WRITE,
        /// <summary>
        /// 读数据
        /// </summary>
        READ
    }

    public class PipeReadDataEventArgs: EventArgs
    {
        byte[] _data;
        int _nDataLength=0;
        public PipeReadDataEventArgs(byte[] buf,int nLen)
        {
            _data = new byte[nLen];
            Array.Copy(buf, _data, nLen);
            _nDataLength = nLen;
        }

        /// <summary>
        /// 返回从管道中读取的字节数组
        /// </summary>
        public byte[] Data { get { return _data; } }

        /// <summary>
        /// 返回管道中读取的字节数组长度
        /// </summary>
        public int DataLength { get { return _nDataLength; } }
    }

    public class PipeErrorEventArgs:EventArgs
    {
        PipeErrorReson _pipeErrorReson ;
        string _msg;
        public PipeErrorEventArgs(PipeErrorReson pipeErrorReson,string msg)
        {
            _pipeErrorReson = pipeErrorReson;
            _msg = msg;
        }
        
        /// <summary>
        /// 返回错误引起的原因【由哪个动作导致的错误】
        /// </summary>
        public PipeErrorReson ErrorReson { get { return _pipeErrorReson; } }

        /// <summary>
        /// 返回错误信息描述
        /// </summary>
        public string Message { get { return _msg; } }
    }

}

 测试界面:

NamedPipeServerStream释放超时时间 namedpipeclientstream_sed

NamedPipeServerStream释放超时时间 namedpipeclientstream_sed_02