好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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" , 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测试数据bine(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 = 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;

   }

  }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持服务器之家!

原文链接:http://HdhCmsTestcnblogs测试数据/crwy/p/6568871.html

dy("nrwz");

查看更多关于c#进程之间对象传递方法的详细内容...

  阅读:47次