C#如何使用SendMessage安全的跨线程,跨进程传递任意对象

首先定义一个基础消息结构体用于消息传递封包

  /// <summary>
    /// 基础消息结构体
    /// </summary>
    public struct WindowsLparamStruct
    {
        /// <summary>
        /// 是否释放大于0表示内存没有被释放
        /// </summary>
        public int State;
        /// <summary>
        /// 指向被序列化对象的指针
        /// </summary>
        public IntPtr BytePrt;
        /// <summary>
        /// 序列化对象的字节长度
        /// </summary>
        public int Length;
    }

然后新建一个对象成员是调用SendMessage API

    public class WindowApis
    {
        /// <summary>
        /// 自定义消息起始
        /// </summary>
        public static int CunstomMessage = 0X400 + 2;
        /// <summary>
        /// 同步发送消息
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// 异步发送消息
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="Msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("User32.dll", EntryPoint = "PostMessage")]
        public static extern int PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    }

然后封装发送消息都类

 public class WindowsMessageHandler 
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public WindowsMessageHandler()
        {
            
        }
//是否异步
private bool IsAsynchronous; /// <summary> /// 窗口句柄 /// </summary> public IntPtr WindowHandle; /// <summary> /// 窗体消息 /// </summary> public WindowsMessage WindMsg; /// <summary> /// 将对象序列化成BYTE数组 /// </summary> /// <param name="obj"></param> /// <returns></returns> private byte[] SeriObjectToBytes(object obj) { byte[] objBuffer = null; using (MemoryStream ms = new MemoryStream()) { //序列化操作,把内存中的东西写到硬盘中 BinaryFormatter fomatter = new BinaryFormatter(); fomatter.Serialize(ms, obj); objBuffer = ms.GetBuffer(); } return objBuffer; } /// <summary> /// 发送 /// </summary> /// <returns></returns> public override int Send() { return this.Send(this.WindowHandle, this.SendObject, this.WindMsg, this.IsAsynchronous); } /// <summary> /// 添加节点 /// </summary> /// <param name="nd"></param> private void PushBuffer(IntPtr objptr, IntPtr bufferptr) { BufferNode bn = new BufferNode(); bn.BufferPtr = bufferptr; bn.ObjectPtr = objptr; BufferNodes.Enqueue(bn); } /// <summary> /// 关闭BUFFER /// </summary> private void CleanBuffer() { while (BufferNodes.Count > 0) { BufferNode nd = BufferNodes.Dequeue(); Marshal.FreeHGlobal(nd.ObjectPtr); Marshal.FreeHGlobal(nd.BufferPtr); } } /// <summary> /// 将序列化成BYTE数组都对象拷贝到消息结构体 /// </summary> /// <param name="objBuffer"></param> /// <returns>返回消息结构体都指针</returns> private IntPtr BuildWslPtr(byte[] objBuffer) {
//第一步是把WindowsLparamStruct的BytePtr指针成员指向序列化之后的数组首地址并记录地址都大小 WindowsLparamStruct wls
= new WindowsLparamStruct();//传送结构体 wls.Length = objBuffer.Length;//序列化对像数组长度 wls.BytePrt = Marshal.AllocHGlobal(objBuffer.Length);//开辟数组大小的空间 Marshal.Copy(objBuffer, 0, wls.BytePrt, wls.Length);//将序列化成BYTE数组的obj对象成员拷贝到结构体指针地址

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(wls));//给传送结构体指针分配obj对象大小的内存 Marshal.StructureToPtr(wls, ptr, true); //把结构体的拷贝到指针指指向的内存 this.PushBuffer(ptr, wls.BytePrt);//指针入队方便统一清理内存防止内存泄漏 return ptr;//返回传送结构体指针 } /// <summary> /// 发送结构体数据 /// </summary> /// <param name="windKey">窗口句柄</param> /// <param name="obj">需要发送的结构体</param> /// <param name="isAnaly">true表示异步否则同步</param> /// <returns></returns> private int Send(IntPtr handle, object obj, WindowsMessage msg, bool isAnaly = false) { int result = 0;//用于返回结果 IntPtr ptr = BuildWslPtr(SeriObjectToBytes(obj)); ptr = BuildWslPtr(SeriObjectToBytes(obj)); try { if (isAnaly == true) { result = WindowApis.PostMessage(handle, WindowApis.CunstomMessage, msg.ToPtr(), ptr); } else { result = WindowApis.SendMessage(handle, WindowApis.CunstomMessage, msg.ToPtr(), ptr); CleanBuffer();//同步情况下可以及时清理内存 } } catch (Exception ex) { result = -1;//出现异常返回-1 } finally { } return result; } }

新建测试对象

  [Serializable]
    public class Mys
    {
        public Mys()
        {
        }
        public int j;
        public long i;
        public byte[] x;
        public string oo;
    }

最后是使用方法

WindowsMessageHandler wmh = new WindowsMessageHandler();       
 private void button1_Click(object sender, EventArgs e)
        {
            wmh.WindowHandle = this.Handle;//接受数据都窗体指针
            wmh.WindMsg = new WindowsMessage("ads");//标记消息名
            wmh.IsAsynchronous = false;
            ThreadPool.QueueUserWorkItem(new WaitCallback(ROC), 0);
        }
//工作线程发送带有数组成员得对象
private void ROC(object obj)
        {
            for (int i = 0; i < 10000; i++)
            {
                Mys mys = new Mys();
                mys.x = new byte[10000];
                mys.oo = "00";
                wmh.SendObject = mys;
                wmh.Send();

            }

        }

接收端窗体消息过程

 protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            if (WindowsMessageHelper.CUSTOM_MESSAGE == msg.Msg)
            {
                if (WindowsMessage.Equals(msg.WParam, "ads"))
                {
                    WindowsLparamStruct res = (WindowsLparamStruct)Marshal.PtrToStructure(msg.LParam, typeof(WindowsLparamStruct));
                    
                    byte[] resByte = new byte[res.Length];//新建序列化对象数组长度的空间
                    Marshal.Copy(res.BytePrt, resByte, 0, res.Length);//从指针地址把对象数组拷贝到新鲜都resBytes
                    MemoryStream ms = new MemoryStream(resByte);//反序列化
                    ms.Position = 0;
                    BinaryFormatter formatter = new BinaryFormatter();
                    Mys obj = (Mys)formatter.Deserialize(ms)
                }


            }
            base.WndProc(ref msg);//调用基类函数处理非自定义消息。
        }

猜你喜欢

转载自www.cnblogs.com/Isesame/p/11161493.html