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;
    }

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

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

时间: 2024-10-15 04:33:19

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

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

转自:http://www.jb51.net/article/37227.htm 本篇文章是对activity之间数据传递的方法进行了详细的分析介绍,需要的朋友参考下 1  基于消息的通信机制 Intent--------boudle,extra用这种简单的形式,一般而言传递一些简单的类型是比较容易的,如int.string等详细介绍下Intent机制Intent包含两部分:1 目的[action]-------要去到哪里去2 内容[category.data]----------路上带些什么,

进程对象的其他方法、守护进程、使用多进程实现 socket tcp协议 server端的并发(抢票程序)、队列、进程之间的通信(IPC)

# 进程对象的其他方法 from multiprocessing import Process import time class MyProcess(Process): def __init__(self, a, b): # 为了给子进程传递参数 super().__init__() self.a = a self.b = b def run(self): print("子进程开始执行") time.sleep(2) print("子进程结束", self.a,

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

主张 什么时候service通常被称为远程时的,用到aidl来定一个接口供service和client来使用.这个事实上就是使用Binder机制的IPC通信. 当client bind service成功之后.系统AM会调用回调函数onServiceConnected将service的IBinder传递给client, client再通过调用aidl生成的asInterface()方法获得service的调用接口.此时一个bind过程结束了.我们在client端就能够远程调用service的方法

Android间的进程通讯(传递复杂对象)

Android间的进程通讯(传递复杂对象) 完成对复杂对象的序列化 在Android中传递复杂数据类型的时候要通过将序列化,在Android中提供了一个接口Parcelable来实现对对象的序列化. 下面对需要传输的对象进行序列化操作,首先看自定义的类Person. package com.example.service_parcelable_conmmute.bean; import android.graphics.Bitmap; /** * 用来传输的对象结构 * @author Xiny

Servlet页面间对象传递的方法

Servlet页面间对象传递的方法 1.request 2.session 3.application 4.cookie 5.其他的 Servlet页面间对象传递的方法,布布扣,bubuko.com

UNIX进程之间传递文件描述符recvmsg与sendmsg

socketpair: 功能:创建一个全双工的流管道 原型 int socketpair(int domain, int type, int protocol, int sv[2]); 参数 domain: 协议家族 type: 套接字类型 protocol: 协议类型 sv: 返回套接字对 返回值:成功返回0:失败返回-1 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t recvmsg(int

1,对象的存储细节,2,#pragma mark指令,3,函数和对象方法的区别,4,对象和方法之间的关系 ,5.课堂习题

1,对象的存储细节, 1. 当创建一个对象的时候:Person *p1 = [Person new],做了三件事情: 1,申请堆内存空间: 2,给实例变量初始化: 3,返回所申请空间的首地址; 2. 实例变量保存在堆区 3. 对象方法保存在代码区 4. 一个类可以创建多个对象: 2,#pragma mark指令, 功能:对代码分组,方便代码查找和导航 使用格式: #pragma mark - #waring 等待处理的功能,或者是未完成的功能 3,函数和对象方法的区别, 一. 对象方法: -(v

0707 父子进程之间传递文件描述符

1 /************************************************************************* 2 > File Name: pass_fd.c 3 > Author:Monica 4 > Mail:[email protected] 5 > Created Time: Mon 07 Jul 2014 09:52:49 PM CST 6 ********************************************

李洪强iOS开发之OC[018]对象和方法之间的关系

// //  main.m //  18 - 对象和方法之间的关系 // //  Created by vic fan on 16/7/14. //  Copyright © 2016年 李洪强. All rights reserved. // /** * OC有参有返回值的方法 有参有返回值方法的声明 - (int)sum:(int)x andY:(int)y; - (int)sum:(int)x andY:(int)y{ return x+y; 关系: 1 对象作为方法的参数; 显示人的信息