c#进程之间对象传递方法
作者:楚人无衣 发布时间:2022-04-22 09:41:10
1. 起源
KV项目下载底层重构升级决定采用独立进程进行Media下载处理,以能做到模块复用之目的,因此涉及到了独立进程间的数据传递问题。
目前进程间数据传递,多用WM_COPYDATA、共享dll、内存映射、Remoting等方式。相对来说,WM_COPYDATA方式更为简便,网上更到处是其使用方法。
而且Marshal这个静态类,其内置多种方法,可以很方便实现字符串、结构体等数据在不同进程间传递。
那么,对象呢?如何传递?
2、序列化
想到了,Newtonsoft.Json.dll这个神器。相对于内建的XmlSerializer这个东西,我更喜欢用Json。
那么,如此处理吧,我们来建个Demo解决方案,里面有HostApp、ClildApp两个项目,以做数据传递。
3、ChildApp项目
先说这个,我没有抽取共用的数据单独出来,而做为Demo,直接写入此项目中,HostApp引用此项目,就可引用其中public出来的数据类型。
数据结构部分代码:
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
[Serializable]
public class Person
{
private string name;
private int age;
private List<Person> children;
public Person(string name, int age)
{
this.name = name;
this.age = age;
this.children = new List<Person>();
}
public string Name
{
get { return this.name; }
set { this.name = value; }
}
public int Age
{
get { return this.age; }
set { this.age = value; }
}
public List<Person> Children
{
get { return this.children; }
}
public void AddChildren()
{
this.children.Add(new Person("liuxm", 9));
this.children.Add(new Person("liuhm", 7));
}
public override string ToString()
{
string info = string.Format("姓名:{0},年龄:{1}", this.name, this.age);
if (this.children.Count != 0)
{
info += (this.children.Count == 1) ? "\r\n孩子:" : "\r\n孩子们:";
foreach (var child in this.children)
info += "\r\n" + child.ToString();
}
return info;
}
}
窗体代码:
public partial class ChildForm : Form
{
public const int WM_COPYDATA = 0x004A;
private IntPtr hostHandle = IntPtr.Zero;
Person person = new Person("liujw", 1999);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
IntPtr hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
ref COPYDATASTRUCT lParam // second message parameter
);
public ChildForm(string[] args)
{
InitializeComponent();
if (args.Length != 0)
this.hostHandle = (IntPtr)int.Parse(args[0]);
}
private void btnSubmit_Click(object sender, EventArgs e)
{
this.person.Name = txtName.Text;
int age;
this.person.Age = int.TryParse(txtAge.Text, out age) ? age : 0;
this.person.AddChildren();
if (this.hostHandle != IntPtr.Zero)
{
string data = GetPersionStr();
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)901;
cds.cbData = data.Length + 1;
cds.lpData = data;
SendMessage(this.hostHandle, WM_COPYDATA, 0, ref cds);
}
}
private string GetPersionStr()
{
return JsonConvert.SerializeObject(this.person);
}
}
这样在窗体按钮btnSubmit_Click事件中,完成了数据向HostApp的字符串形式传递。
如何获取宿主程序的窗口句柄呢?改造下ChildApp的Program.cs过程即可:
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ChildForm(args));
}
3、HostApp项目
我们权且称之为宿主项目吧,其窗体代码为:
public partial class MainForm : Form
{
public const int WM_COPYDATA = 0x004A;
public MainForm()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT copyData = new COPYDATASTRUCT();
Type type = copyData.GetType();
copyData = (COPYDATASTRUCT)m.GetLParam(type);
string data = copyData.lpData;
RestorePerson(data);
break;
}
}
private void RestorePerson(string data)
{
var person = JsonConvert.DeserializeObject<Person>(data);
if (person != null)
txtInfo.Text = person.ToString();
}
private void btnSubmit_Click(object sender, EventArgs e)
{
RunChildProcess();
}
private void RunChildProcess()
{
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
string childPath = Path.Combine(appPath, "ChildApp.exe");
Process.Start(childPath, this.Handle.ToString());
}
}
它的作用就是接收子进程传递回来的字串,用JsonConvert反序列化为Person对象。
是不是很简单呢?
其实就是用了WM_COPYDATA的字符串传递功能,加上Json的序列化、反序列化,而实现c#不同进程间的对象传递
4、效果图:
5、2017-03-24追加:
今天又发现用Json序列化较为复杂的字串时,出现转义错误,导致反序列化失败。于时改用二进制序列化,转其为base64字串进行传递,问题解决。
代码如下:
public static class SerializeHelper
{
/// <summary>
/// 序列obj对象为base64字串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string Serialize(object obj)
{
if (obj == null)
return string.Empty;
try
{
var formatter = new BinaryFormatter();
var stream = new MemoryStream();
formatter.Serialize(stream, obj);
stream.Position = 0;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
return Convert.ToBase64String(buffer);
}
catch (Exception ex)
{
throw new Exception(string.Format("序列化{0}失败,原因:{1}", obj, ex.Message));
}
}
/// <summary>
/// 反序列化字符串到对象
/// </summary>
/// <param name="str">要转换为对象的字符串</param>
/// <returns>反序列化出来的对象</returns>
public static T Deserialize<T>(string str)
{
var obj = default(T);
if (string.IsNullOrEmpty(str))
return obj;
try
{
var formatter = new BinaryFormatter();
byte[] buffer = Convert.FromBase64String(str);
MemoryStream stream = new MemoryStream(buffer);
obj = (T)formatter.Deserialize(stream);
stream.Close();
}
catch (Exception ex)
{
throw new Exception(string.Format("序列化{0}失败,原因:{1}", obj, ex.Message));
}
return obj;
}
}
来源:http://www.cnblogs.com/crwy/p/6568871.html


猜你喜欢
- 在使用xutils时遇到不能添加以来的问题,花了很长时间终于解决,网上添加依赖的方法很多,在此针对个人出现的问题作下笔记。我本想使用jar包
- Redis缓存中间件缓存是什么  所谓缓存就是数据交换的缓冲区(称作Cache [ k&aeli
- 一、 添加 maven 依赖<dependency> <groupId>com.google.guava
- 前言在前面的篇章中,对Java语言的简单数据类型、数组、运算符和表达式以及流程控制的方法做了详细介绍。从本章开始,我们正式介绍面向对象的程序
- 最近正式入坑Flutter,首先从环境搭建开始,看了网上好多关于Windows环境搭建的资料,基本都是按官方文档写的,看完的感受是,还不如直
- 首先:我们要建一个web项目接着: 我们先来导入struts的xml文件第一步:右击你的项目名,鼠标到MyEclipse会看到一个add s
- 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下:一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区:ja
- 目录一、背景二、推荐方式2.1 自定义的枚举2.2 外部枚举三、总结一、背景平时工作开发过程中,难免会用到状态机(状态的流转)。如奖学金审批
- 本文主要内容:•1、什么是Cookie•2、Cookie带来的好处•3、Cookie的主要方法 一、什么是Cookiecookie
- java 算法之快速排序实现代码摘要: 常用算法之一的快速排序算法的java实现原理:选择一个基准元素,通常选择第一个元素或者最后一个元素,
- Spring容器可以自动装配相互协作bean之间的关系,这有助于减少对XML配置,而无需编写一个大的基于Spring应用程序的较多的<
- DataGridView:显示数据表后台数据绑定:List<xxx> list = new List<xxx>();
- 前言现代化大型项目通常使用独立的数据库来存储数据,其中以采用关系型数据库居多。用于开发项目的高级语言(C#、Java等)是面向对象的,而关系
- 本文实例讲述了java获取百度网盘真实下载链接的方法。分享给大家供大家参考。具体如下:目前还存在一个问题,同一ip在获取3次以后会出现验证码
- 目录创建线程管理线程销毁线程创建线程线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开
- 用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧? 其实实现这种功能,主要有两步: 1.判断
- 一.问题1.HashSet,TreeSet是如何使用hashCode()和equal()方法的2.TreeMap,TreeSet中的对象何时
- 我们都知道,在我们开发时需要在模拟器上模拟GPS,可在Location的时候总是null,上网查了一下,发现如下解决: 网上大侠的解决方案:
- 简介switch的新特性可是源远流长,早在JDK 12就以预览功能被引入了,最终在JDK 14成为了正式版本的功能:JEP 361: Swi
- 常用:System:根空间,包含一些基本的类库 System.Collections:主要是和集合类相关的类库 System.Collect