1. 起源
kv项目下载底层重构升级决定采用独立进程进行media下载处理,以能做到模块复用之目的,因此涉及到了独立进程间的数据传递问题。
目前进程间数据传递,多用wm_copydata、共享dll、内存映射、remoting等方式。相对来说,wm_copydata方式更为简便,网上更到处是其使用方法。
而且marshal这个静态类,其内置多种方法,可以很方便实现字符串、结构体等数据在不同进程间传递。
那么,对象呢?如何传递?
2、序列化
想到了,newtonsoft.json.dll这个神器。相对于内建的xmlserializer这个东西,我更喜欢用json。
那么,如此处理吧,我们来建个demo解决方案,里面有hostapp、clildapp两个项目,以做数据传递。
3、childapp项目
先说这个,我没有抽取共用的数据单独出来,而做为demo,直接写入此项目中,hostapp引用此项目,就可引用其中public出来的数据类型。
数据结构部分代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
[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; } } |
窗体代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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过程即可:
1
2
3
4
5
6
7
8
9
10
|
/// <summary> /// 应用程序的主入口点。 /// </summary> [stathread] static void main( string [] args) { application.enablevisualstyles(); application.setcompatibletextrenderingdefault( false ); application.run( new childform(args)); } |
3、hostapp项目
我们权且称之为宿主项目吧,其窗体代码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
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字串进行传递,问题解决。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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://www.cnblogs.com/crwy/p/6568871.html