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
猜你喜欢
- Java程序设计 图形用户界面【四】按钮组件 JButtonJButton组件表示一个普通的按钮JButton类常用方法方法作用public
- maven周期maven的生命周期不止package,compile,clean。其实这是主要部分。以下截图其实展示的是maven的所有周期
- 定义栈又名堆栈,是一种操作受限的线性表,仅能在表尾进行插入和删除操作。它的特点是先进后出,就好比我们往桶里面放盘子,放的时候都是从下往上一个
- 1、前言当提及如何终止一个线程时,部分读者通常立马想到的方法肯定是stop(),但是stop()方法并不被推荐使用(很多规范中是禁止使用的)
- 一、抽象类是什么?在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的
- 递归方法定义本身调用方法本身的现象叫做递归在这之前我们学的东西:例如StringBuffer.append().append().appen
- 一,下载Zookeeper,地址为http://archive.apache.org/dist/zookeeper/,找到你要下载的版本,我
- 一、文件存储特点:openFileInput()和openFileOutput()读取设备上的文件。优点:适用于存储大量的数据,可以存储图片
- mybatis-plus实现in嵌套sql今天使用jeegboot看源码时发现用户权限部分的代码条件查询的inSql方法的用法:即sql中的
- C#是托管型代码,创建的对象会自动回收。C++是非托管型代码,创建的对象需要手动回收(有时不手动回收,可能出现内存溢出的问题)。C#调用C+
- 类加载子系统classLoader 只负责对字节码文件的加载,至于是否可以运行,还要看执行引擎。加载的类信息存放于方法区的内存空间,除了类信
- 一.简单介绍1.配置相关的依赖2.配置模式3写.mapper、controller、service4.配置yaml文件 配置mybatis全
- 1. JAVA 内存模型 (JMM)JMM是用来干嘛的?:《Java虚拟机规范》中曾试图定义一种“Java内存模型&am
- 本文实例讲述了Android实现将应用崩溃信息发送给开发者并重启应用的方法。分享给大家供大家参考,具体如下:在开发过程中,虽然经过测试,但在
- Maven热部署,顾名思义就是可以不影响项目在服务器中的运行情况,可以实现项目代码的更新,减少启动,编译时间,达到快速开发的目的,也不需要手
- 1. Spring简介Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。2. Spring的优势 1.方便解耦, 简
- 具体代码如下所示:import java.io.File;public class Scan { public static v
- 昨天在与对端系统调接口的时候,对端系统对我们传过去的json串老是处理不了,后来查原因是应为我们传过去的json串里有json对象数组,因为
- 对这种懒加载问题,最后的做法是利用Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibern
- 一、线程池简介线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供更好的性能,在不使用线程池时候,每当需要执行异步任务的