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