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. Mac系统安装Aircrack-ng破解附近wifi密码(1)

    第一步, 安装macport, 安装Xcode 安装macport macport 是一个工具 管理软件包的一个工具, 我们也可以通过别的方式安装Aircrack-ng, 但是通过macport安装A ...

  2. Android 隐藏软键盘

    隐藏软键盘 public void hideSoftInputView() { InputMethodManager manager = ((InputMethodManager) this.getS ...

  3. 利刃 MVVMLight 3:双向数据绑定

          上篇我们已经了解了MVVM的框架结构和运行原理.这里我们来看一下伟大的双向数据绑定. 说到双向绑定,大家比较熟悉的应该就是AngularJS了,几乎所有的AngularJS 系列教程的开篇 ...

  4. (五)Hololens Unity 开发之 手势识别

    学习源于官方文档 Gestures in Unity 笔记一部分是直接翻译官方文档,部分各人理解不一致的和一些比较浅显的保留英文原文 (五)Hololens Unity 开发之 手势识别 HoloLe ...

  5. 蓝桥网试题 java 基础练习 杨辉三角形

    ----------------------------------------------------------- ---------------------------------------- ...

  6. <C++Primer>第四版 阅读笔记 第三部分 “类和数据抽象”

    类定义了数据成员和函数成员:数据成员用于存储与该类类型的对象相关联的状态:而函数成员则负责执行赋予数据意义的操作. 第12章 类 一个类可以包含若干公有的.私有的和受保护的部分:在public部分定义 ...

  7. sqlite数据库学习

    1.0版代码: package com.swust.sqlitedatabase.test; import com.swust.sqlitedatabase.myOpenHelper; import ...

  8. C# 多态理论基础

    一.概述 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性. 可以用不同的方式实现组件中的多态性: ● 接口多态性. ● 继承多态性. ● 通过抽象类实现的多态性. 二.实 ...

  9. ES6__异步开发优化

    一:JS事件循环 1:同步调用 同步调用是一种阻塞式调用,调用要等待双方执行完毕才返回,他是一种单向调用. 2:回调 回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口. 3: ...

  10. selenium框架与chrome浏览器的不兼容问题

    在一次偶然的情况下,在chrome上用selenium框架去抓取某个id为XX的页面元素,使用WebDriver的findElement().click()方法进行点击,原来在firefox浏览器运行 ...