c#进程之间对象传递方法
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#进程之间对象传递方法的更多相关文章
- 解析activity之间数据传递方法的详解
转自:http://www.jb51.net/article/37227.htm 本篇文章是对activity之间数据传递的方法进行了详细的分析介绍,需要的朋友参考下 1 基于消息的通信机制 ...
- jsp页面间对象传递方法
严格的来说不能叫做JSP页面间的对象传递,实际应该是页面间对象共享的方法: 1. 通过servletcontext,也就是application对象了,但这种情况要求在同一个web应用下, ...
- 使用copydata实现进程之间数据传递
Winform to Winfrom==> 发送端==> using System; using System.Runtime.InteropServices; namespace Cop ...
- VUE2.0 饿了吗视频学习笔记(五):父子对象传递、显示图片
一.父子组件之间对象传递 1.app.Vue中的v-header 中加入 v-bind:seller="seller" template> <div id=" ...
- 并发编程 ~~~ 多进程~~~进程创建的两种方式, 进程pid, 验证进程之间的空间隔离, 进程对象join方法, 进程对象其他属性
一 进程创建的两种方式 from multiprocessing import Process import time def task(name): print(f'{name} is runnin ...
- IBinder在进程之间传递一个对象的形式(一)
主张 什么时候service通常被称为远程时的,用到aidl来定一个接口供service和client来使用,这个事实上就是使用Binder机制的IPC通信.当client bind service成 ...
- 用WM_COPYDATA消息来实现两个进程之间传递数据
文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据. 进程之间通讯的几种方法:在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有 1.使用内存映射 ...
- 在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程。
在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程. 答案:可以通过Intent对象.静态变量.剪切板和全局对象进行数据传递,具体的数据传递方法如下. 1. ...
- python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程
python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 目录 python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 ...
随机推荐
- 2016 ACM/ICPC Asia Regional Qingdao Online(2016ACM青岛网络赛部分题解)
2016 ACM/ICPC Asia Regional Qingdao Online(部分题解) 5878---I Count Two Three http://acm.hdu.edu.cn/show ...
- MySQL 存储表情字符
摘要 在 MySQL 中直接存储表情的时候,会出现无法插入数据的错误. 这是由于一般情况下,MySQL 的字符集是 utf8,而对于 emoji 表情的 mysql 的 utf8 字符集是不支持,需要 ...
- js面试题-2
// 1.截取字符串 var aa = "abcd"; console.log(aa.substr(,)); var str = "qweda"; consol ...
- Oracle VS DB2 数据类型
=========================Oracle VS DB2==================================== 本文转自:http://www.bitscn.co ...
- Linux系统(三)系统基础扫盲大全
序言 如果大家都爱装逼,一般会偏爱使用安装最小化的liunx系统,那么你的系统就不带图形化的桌面功能,这样对于一个想装B的初学者来说,Liunx就是黑漆马虎,一望无际的黑屏,黑屏,如何快速的对liun ...
- WPScan初体验
近日在朋友圈看某位dalao在Ubuntu上安装WPScan花了一个小时,于是洒家随手在Kali Linux上输入了wpscan,发现Kali里面已经装好了.于是决定玩两把WPScan. WordPr ...
- Java初学练习答案(循环)
/* 题目如下: 1 (for 循环)*编程找出四位整数abcd 中满足下述关系的数. (ab+cd)(ab+cd)=abcd 2 (循环)*读入一个整数n,输出如下图形 n = 3 * *** ** ...
- PHP文件上传处理
web中,文件上传是一个很常用的功能.如:上传头像.上传图片.这些提交到后台的图片都要交给后端处理.php提供了几个上传处理的函数,我把它们封装成类,以便日后使用. 处理流程(可能有不合理的地方,用时 ...
- 简述.jpg .Gif .png-8 .png-24的区别
最近有很多朋友在开发过程中有时候会遇到图片加载不清晰,透明度失真,或者对图片进行操作之后造成图片损耗的现象,在这里给大家简单介绍一下常用的几种图片格式之间的区别 Gif格式特点: 1.透明性,Gif是 ...
- Oracle排序分析函数
在Oracle自拓展SQL功能中,分析函数(Analytical Function)是非常强大的工具. 本篇我们介绍几个Oracle典型的排序分析函数,来帮助我们解决实际问题. 1.从rownum谈起 ...