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方法.进程对象属性.守护进程 ...
随机推荐
- Wireshark网络抓包(一)——数据包、着色规则和提示
一.数据包详细信息 Packet Details面板内容如下,主要用于分析封包的详细信息. 帧:物理层.链路层 包:网络层 段:传输层.应用层 1)Frame 物理层数据帧概况 2)Ethernet ...
- Professional C# 6 and .NET Core 1.0 - What’s New in C# 6
本文为转载,学习研究 What's New in C# 6 With C# 6 a new C# compiler is available. It's not only that a source ...
- nRF51800 蓝牙学习 进程记录 1:感想
一直想开一个高大上点的博客,觉得博客园不错,便申请了.一直没时间看,都快忘了,无意间登上提示申请到了.便写个东西看看. 正在学习nRF51822的蓝牙开发板,为了做毕设准备.备考中,一直没时间学,但今 ...
- SQL CRUD 简单查询
identity 自增长 primary key 主键 unique 唯一键 not null 非空 references 外键(引用) 1.删除表 drop table Student 2.修改表 ...
- JavaScript易混淆知识点小回顾--数组方法与字符串方法;
数组属性: arr.length;查看数组的长度 arr.Pop;删除数组最后一个元素; 数组的方法: arr.push();添加到数组末端; arr.shift();删除数组的第一个元素; arr. ...
- MySql学习(七) —— 查询性能优化 深入理解MySql如何执行查询
本篇深入了解查询优化和服务器的内部机制,了解MySql如何执行特定查询,从中也可以知道如何更改查询执行计划,当我们深入理解MySql如何真正地执行查询,明白高效和低效的真正含义,在实际应用中就能扬长避 ...
- Node - EJS模板应用(node+express+ejs)
准备工作: 工具:Webstorm 1. 新建一个文件夹为blogs(随意). 一个js文件app.js. 一个文件夹views,文件夹内一个index.ejs文件,文件夹asstes内style.c ...
- 深入理解javaScript的深复制和浅复制
javascript有五种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Number和String.还含有一种复杂数据类型,就是对象 注意Undefin ...
- 在GlassFish应用服务器上创建并运行你的第一个Restful Web Service【翻译】
前言 本人一直开发Android应用,目前Android就业形势恶劣,甚至会一路下滑,因此决定学习服务器开发.采用的语言是java,IDE是Intellij,在下载Intellij的同时看到官网很多优 ...
- jxls2.3-简明教程
jxls是一个简单的.轻量级的excel导出库,使用特定的标记在excel模板文件中来定义输出格式和布局.java中成熟的excel导出工具有pol.jxl,但他们都是使用java代码的方式来导出ex ...