首页 > 系统相关 >C# 进程之间对象传递方法

C# 进程之间对象传递方法

时间:2022-10-06 22:32:57浏览次数:38  
标签:obj string C# 传递 int 进程 new 序列化 public


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、效果图:

C# 进程之间对象传递方法_json

5、追加:

今天又发现用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; } }

参考网址:

源码下载地址 百度网盘

链接:https://pan.baidu.com/s/1_wCdEeY6LKSPDB4jHB-VSw 

提取码:5m7m 

标签:obj,string,C#,传递,int,进程,new,序列化,public
From: https://blog.51cto.com/biyusr/5734120

相关文章