我是靠谱客的博主 漂亮山水,最近开发中收集的这篇文章主要介绍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);//调用基类函数处理非自定义消息。
}

 

转载于:https://www.cnblogs.com/Isesame/p/11161493.html

最后

以上就是漂亮山水为你收集整理的C#如何使用SendMessage安全的跨线程,跨进程传递任意对象的全部内容,希望文章能够帮你解决C#如何使用SendMessage安全的跨线程,跨进程传递任意对象所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部