C#调用C++的dll方法,返回值为结构

hb9191 2009-04-28 03:02:38
c++的D.dll里定义:

typedef struct
{
char a[10];
long b;
}SS;
SS funA(char *p1,long p2);

C#里:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RESULT
{
public byte[] a;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AnsiBStr, SizeConst = 10)]
public int b;
}
[DllImport("D.dll", EntryPoint = "funcA", CharSet = CharSet.Ansi)]
public static extern RESULT func_A(StringBuilder p1,int p2);

StringBuilder p1=new StringBuild("fff");
RESULT res = func_A(p1,111);
运行到这儿,直接退出!没有任何提示!

请教高手!
谢谢!
...全文
340 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
hubin1225 2009-07-16
  • 打赏
  • 举报
回复
我也遇到同样的问题
xiaomiyinerzhou 2009-05-13
  • 打赏
  • 举报
回复
你的问题主要就是平台调用过程中的数据封送问题。楼上有人已经给出了正确的答案。但是如果只获得答案,不知道原理,以后遇到了此类问题还是不知道如何下手。

如果你想系统学习如何进行数据封送,我推荐你阅读刚刚出版的新书:《精通.NET互操作P/Invoke,C++Interop和COM Interop》,这本书的第2章“数据封送”详细介绍了平台调用中的数据封送过程,非常详细,我就是读完后才搞清楚平台调用中的封送处理。


该书的官方网站:
www.interop123.com

豆瓣网信息:
http://www.douban.com/subject/3671497/
gomoku 2009-04-29
  • 打赏
  • 举报
回复
更正:
struct A32
{
public long a,b,c,d;
}
gomoku 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 hb9191 的回复:]
十分感谢两位的帮助!

按照我对上面的理解,我就有点不幸了?!

我实践应用中有两个char[4001]和一个char[1001]!
要建2253个“傀儡”??!!!

如果long型能用也要1147个?!
[/Quote]

返回一个非常大的结构是设计上的失误 - 结构都是按拷贝传参的,拷贝大结构成本不小。


如果一定要做,或许这样(看着难受):
struct A64
{
public long a,b,c,d;
}
struct A256
{
public A64 a,b,c,d;
}


另,谢谢agentianle的讲解,比我的生动多了。
hb9191 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 qqiuzaihui 的回复:]
可以在C++中使用 CreateFileMapping 将结构体数据直接写进内存,
然后在C#中使用 OpenFileMapping 在指定的内存地址获取数据.
[/Quote]

要是能修改DLL,就不要这么麻烦了,只要修改返回值类型,把结构变为出参就行了。
qqiuzaihui 2009-04-29
  • 打赏
  • 举报
回复
可以在C++中使用 CreateFileMapping 将结构体数据直接写进内存,
然后在C#中使用 OpenFileMapping 在指定的内存地址获取数据.
hb9191 2009-04-29
  • 打赏
  • 举报
回复
十分感谢两位的帮助!

按照我对上面的理解,我就有点不幸了?!

我实践应用中有两个char[4001]和一个char[1001]!
要建2253个“傀儡”??!!!

如果long型能用也要1147个?!
天乐 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 gomoku 的回复:]
C++中char a[10]占十个字节,加上对齐成4的倍数,为12个字节。
C#中的三个int也占12个字节。

struct不会变成指针的,C#里仍定义为struct。
[/Quote]

哈哈,再次更正11楼的更正,忘了字节对齐的事情了

关于char a[10]的转换占用空间,以10楼为正解
天乐 2009-04-29
  • 打赏
  • 举报
回复
更正9楼的一个说法有误:
作为string来说,还有个结束符'\0',所以你的char a[10]转为string后最多需要占用到11个字节的空间。
--->
这里char a[10]转为string后最多需要占用到10个字节的空间。若有'\0'应是在char a[10]内部

基于9楼的解释,为5楼的代码再添加点注释

// 结构成员都是Blittable,dummy们是占位的傀儡
[StructLayout(LayoutKind.Sequential)]
public struct RESULT
{
public int dummy1, dummy2, dummy3; //申请到12字节内存,用于接收char[10] a
public int b; //申请4字节内存,对应long b

public string a //属性a,对应char[10] a,用于外部使用
{
get
{
//外部访问此string a时,把3个dummy里面存储的数据转换为c#里面的string

List<byte> bytes = new List<byte>(); //用于临时存储转换过程中的数据
bytes.AddRange( BitConverter.GetBytes(dummy1) ); //把dummy1按字节存入bytes,下同
bytes.AddRange( BitConverter.GetBytes(dummy2) );
bytes.AddRange( BitConverter.GetBytes(dummy3) );

//把bytes按ASCII码转为字符串并返回
//注意bytes.IndexOf(0)这里的意思是如果字节中有0即'\0',则表示字符串已结束
//这里不太严谨,假设了你的char[10]是作为字符串用的,如果你不是这样子(没'\0'),需要自行处理
return Encoding.ASCII.GetString(bytes.ToArray(), 0, bytes.IndexOf(0));
}
}
}

gomoku 2009-04-29
  • 打赏
  • 举报
回复
C++中char a[10]占十个字节,加上对齐成4的倍数,为12个字节。
C#中的三个int也占12个字节。

struct不会变成指针的,C#里仍定义为struct。
天乐 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hb9191 的回复:]
在下水平不足,没懂:
dummy1, dummy2, dummy3的值怎么来?
为什么是3个?跟char a[10] 有关系吗?
另外,在C#里仍是定义为struct?

谢谢
[/Quote]

帮你解释一下5楼的意思

1、关于dummy1, dummy2, dummy3
5楼说“dummy们是占位的傀儡”,意思就是三个int纯粹是为了占位即申请内存空间而设置的,
你要是高兴,弄上几个short,或者1个1个的byte也无不可

2、为什么是3个?跟char a[10] 有关系吗?
有关系。3个int占了12个字节,比你的char a[10]空间大些才能装得下你的char a[10]。
作为string来说,还有个结束符'\0',所以你的char a[10]转为string后最多需要占用到11个字节的空间。
故此,傀儡们事先占好12个字节的空间,以防止空间不足,也没有过多浪费。

3、在C#里仍是定义为struct
是的

hb9191 2009-04-29
  • 打赏
  • 举报
回复
在下水平不足,没懂:
dummy1, dummy2, dummy3的值怎么来?
为什么是3个?跟char a[10] 有关系吗?
另外,在C#里仍是定义为struct?

谢谢
天乐 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hb9191 的回复:]
首先谢谢回复!

具体到本例
typedef struct
{
char a[10];
long b;
}SS;
怎么做呢?不需要改DLL文件吧(这不可能)?
[/Quote]

5楼不是说的很清楚了么?再多看几遍
天乐 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 hb9191 的回复:]
十分感谢两位的帮助!

按照我对上面的理解,我就有点不幸了?!

我实践应用中有两个char[4001]和一个char[1001]!
要建2253个“傀儡”??!!!

如果long型能用也要1147个?!
[/Quote]

提供一个思路供参考:

鉴于你不能修改c++程序,可以考虑对其进行封装一下。

即,可以用c++做个自己的dll,封装、转换原dll的方法。

这个代理dll可以起到沟通原dll和C#程序的作用。

如此,14楼中所述“可以在C++中使用 CreateFileMapping 将结构体数据直接写进内存, ”

即可在代理dll中实现。

而你则可 “然后在C#中使用 OpenFileMapping 在指定的内存地址获取数据.”

hb9191 2009-04-29
  • 打赏
  • 举报
回复
见到过有人说把struct改为class,但没有说清除。

有人知道吗?
hb9191 2009-04-28
  • 打赏
  • 举报
回复
首先谢谢回复!

具体到本例
typedef struct
{
char a[10];
long b;
}SS;
怎么做呢?不需要改DLL文件吧(这不可能)?
gomoku 2009-04-28
  • 打赏
  • 举报
回复
刚刚检讨了一下P/Invoke返回结构的封送方法,发现问题比想象的复杂多了。

最大的可能是.NET目前只支持返回直接复制到本机结构中的类型(英文叫Blittable type)。
而不支持类型中含有需分配大小的成员(就像那个[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]string a)。
我看到一些类似的提法,但没有从微软的文档中找到依据。

一个变通的方法是把返回的结构成员全部改写成Bittable类型,而用属性来进行自定义转换:

// 结构成员都是Blittable,dummy们是占位的傀儡
[StructLayout(LayoutKind.Sequential)]
public struct RESULT
{
public int dummy1, dummy2, dummy3;
public int b;

public string a
{
get
{
List<byte> bytes = new List<byte>();
bytes.AddRange( BitConverter.GetBytes(dummy1) );
bytes.AddRange( BitConverter.GetBytes(dummy2) );
bytes.AddRange( BitConverter.GetBytes(dummy3) );
return Encoding.ASCII.GetString(bytes.ToArray(), 0, bytes.IndexOf(0));
}
}
}


朋友们谁有更准确的解释和方法,烦请赐教。
hb9191 2009-04-28
  • 打赏
  • 举报
回复
struct作参数,怎么都好说,
作为函数返回值时,就不行了!


用class,怎么用才不运行到调用方法时,直接退出,没有任何提示??
hb9191 2009-04-28
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 gomoku 的回复:]
用AnsiBStr是错的,BSTR是另外一种结构。现这样试:

public struct RESULT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
string a;
public int b;
}
[/Quote]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AnsiBStr, SizeConst = 10)]
public byte[] a;
我用到的struct作参数时,用这个没问题。

改成你上面的样子,只要是struct,就报:“方法的类型签名与 PInvoke 不兼容。”
hb9191 2009-04-28
  • 打赏
  • 举报
回复
更正一:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RESULT
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AnsiBStr, SizeConst = 10)]
public byte[] a;
public int b;
}
更正二:
上面用struct,出错:“方法的类型签名与 PInvoke 不兼容。”
如果用class,才是“运行到这儿,直接退出!没有任何提示!”
加载更多回复(1)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧