• 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);//调用基类函数处理非自定义消息。
            }
  • 相关阅读:
    很多人知道外包的种种不好,但还是选择去外包,这是为什么呢?
    微信聊天内容可以被监听吗
    Go 语言笔试面试题(实现原理)
    oracle中正则表达式相关函数regexp_like简介
    These 30 keyboard shortcuts are guaranteed to save you time in After Effects.
    Why is git submodule not updated automatically on git checkout?
    WPF DataBinding: Nullable Int still gets a validation error?
    How to make a dropdown list of all cultures (but no repeats)
    米象
    How To Bind a Combobox to a Dictionary in WPF C#
  • 原文地址:https://www.cnblogs.com/Isesame/p/11161493.html
Copyright © 2020-2023  润新知