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", ));
this.children.Add(new Person("liuhm", ));
} public override string ToString()
{
string info = string.Format("姓名:{0},年龄:{1}", this.name, this.age);
if (this.children.Count != )
{
info += (this.children.Count == ) ? "\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", ); [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 != )
this.hostHandle = (IntPtr)int.Parse(args[]);
} 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 : ;
this.person.AddChildren(); if (this.hostHandle != IntPtr.Zero)
{
string data = GetPersionStr();
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr);
cds.cbData = data.Length + ;
cds.lpData = data;
SendMessage(this.hostHandle, WM_COPYDATA, , 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 = ;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, , 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;
}
}

Json参考:http://www.newtonsoft.com/json

c#进程之间对象传递方法的更多相关文章

  1. 解析activity之间数据传递方法的详解

    转自:http://www.jb51.net/article/37227.htm 本篇文章是对activity之间数据传递的方法进行了详细的分析介绍,需要的朋友参考下     1  基于消息的通信机制 ...

  2. jsp页面间对象传递方法

    严格的来说不能叫做JSP页面间的对象传递,实际应该是页面间对象共享的方法: 1. 通过servletcontext,也就是application对象了,但这种情况要求在同一个web应用下,      ...

  3. 使用copydata实现进程之间数据传递

    Winform to Winfrom==> 发送端==> using System; using System.Runtime.InteropServices; namespace Cop ...

  4. VUE2.0 饿了吗视频学习笔记(五):父子对象传递、显示图片

    一.父子组件之间对象传递 1.app.Vue中的v-header 中加入 v-bind:seller="seller" template> <div id=" ...

  5. 并发编程 ~~~ 多进程~~~进程创建的两种方式, 进程pid, 验证进程之间的空间隔离, 进程对象join方法, 进程对象其他属性

    一 进程创建的两种方式 from multiprocessing import Process import time def task(name): print(f'{name} is runnin ...

  6. IBinder在进程之间传递一个对象的形式(一)

    主张 什么时候service通常被称为远程时的,用到aidl来定一个接口供service和client来使用,这个事实上就是使用Binder机制的IPC通信.当client bind service成 ...

  7. 用WM_COPYDATA消息来实现两个进程之间传递数据

    文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据. 进程之间通讯的几种方法:在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有   1.使用内存映射 ...

  8. 在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程。

    在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程. 答案:可以通过Intent对象.静态变量.剪切板和全局对象进行数据传递,具体的数据传递方法如下. 1. ...

  9. python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程

    python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 目录 python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 ...

随机推荐

  1. 关于pandas精度控制

    最近使用pandas处理一批数据,数据中包含几个columns,它们的数据精度,例如 3.25165,1451684684168.0,0.23 处理完之后保存csv时发现,1451684684168. ...

  2. 使用Grafana 展示Docker容器的监控图表并设置邮件报警规则

    一.Docker 容器监控报警方式 接着上篇文章的记录,看到grafana的版本已经更新到4.2了,并且在4.0以后的版本中,加入了Alert Notifications 功能,这样在对容器 监控完, ...

  3. C++从string中删除所有的某个特定字符

    C++中要从string中删除所有某个特定字符, 可用如下代码 str.erase(std::remove(str.begin(), str.end(), 'a'), str.end()); 其中, ...

  4. B树的查找、插入、删除(附源代码)

    B-Tree Index B-Tree搜索 B-Tree插入 分裂节点 插入节点 B-Tree删除 合并节点 删除节点 Basic B-Tree有两个比较重要的性质: 所有的leaf均在同一个leve ...

  5. 源码(08) -- java.util.ListIterator<E>

    java.util.ListIterator<E> 源码分析(JDK1.7) ------------------------------------------------------- ...

  6. GTK+基本图元的绘制

    // main.c #include <gtk/gtk.h> static void draw_round_rectangle (cairo_t * cr, double x, doubl ...

  7. Xamarin组件包 Xamarin.ToolKit

    一  简介 Xamarin.ToolKit是个人在使用xamrin.froms开发2年中,因实际项目需要所自定义的组件包.该组件包采用xamarin.froms方式封装,用户可像普通forms控件那样 ...

  8. ICMP(网际控制报文协议)

    为了更有效的提高ip数据报的成功转发和交付的效率,在网际层使用了icmp网际控制报文协议,这个协议允许主机和路由器提供差错和异常情况的报告,icmp不是高层协议,而是网际层的协议,加在ip数据报中一起 ...

  9. java 构造器学习笔记

    构造器(构造器不是方法也不是类的成员) 以前创建对象的方式, public class Constructor{ public static void main(String[] args){ per ...

  10. JTextArea与TextArea自动换行和滚动条的区别对比

    最近在用Java写一个仿记事本的程序,但是发现用JTextArea写的效果有点差,但是用TextArea自动换行并不那么方便,经过对比和实践,我也发现自己对这两个标签认识存在不足,下面就来讨论一下他们 ...