将嵌套的C ++结构编组到托管C#

时间:2013-02-28 21:30:39

标签: marshalling

有关如何将非托管嵌套结构编组到C#DLL中的某些可用数据结构的任何建议吗?我必须更改值,这样我就不能使用Marshal.PtrToStructure制作结构的副本。

C ++结构是正确初始化的,看起来像:

//C++
struct Location
{
   int lat;
   int lon;
};

struct LocationList
{
   Location *loc;
   int id;
};

Location l[2];
LocationList ll;
ll.loc = l;

我可以将它编组到以下原始数据结构中。但它不可用,因为实际上有20个左右的位置结构,而不是示例中的两个,我需要能够遍历它们。

请注意,id的字段偏移量28是C ++编译器构建Location结构的方式。

//C#
[StructLayout(LayoutKind.Explicit)]
unsafe public struct LocationList
{
   [FieldOffset(0)] 
   public int lat0;
   [FieldOffset(4)] 
   public int lon0;
   [FieldOffset(8)]
   public int lat1;
   [FieldOffset(12)]
   public int lon1;
   [FieldOffset(28)]
   public int id;
}

以下情况不起作用 - 字段未正确对齐。我试过变化无济于事,我的caffiene消费量最大化。我只是想用C ++重写DLL,虽然我发誓永远不会。

//C#
[StructLayout(LayoutKind.Explicit)]
unsafe public struct Location
{
    [FieldOffset(0)]
    public int lat;
    [FieldOffset(4)]
    public int lon;
};

[StructLayout(LayoutKind.Explicit)]
unsafe public struct LocationList
{
    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public Location[] loc;
    [FieldOffset(28)]
    public int id;
};

使用指针的解决方案可以,比在C ++中重建整个内容更好。

我在这里和其他地方进行了广泛的搜索,并没有看到一个好的答案。

谢谢,汤姆


汉斯,妈妈,我读错了,但不可能?设置C ++结构值后,这里是上面列出的LocationList结构的内存映射,包含两个Location结构。

l[0].lat = 0xfefefefe;
l[0].lon = 0xdededede;
l[1].lat = 0xfdfdfdfd;
l[1].lon = 0xcdcdcdcd;
ll.id = 0xbabababa;

0x0020FB1C  fe fe fe fe 
0x0020FB20  de de de de
0x0020FB24  fd fd fd fd
0x0020FB28  cd cd cd cd
0x0020FB2C  cc cc cc cc
0x0020FB30  cc cc cc cc
0x0020FB34  1c fb 20 00
0x0020FB38  ba ba ba ba

我不知道编译器在2C,30和34处放置了什么,但很明显id为38,与1C相差28d。

谢谢,汉斯的信息 - 将另外看看它......汤姆


解决!

好的,我感谢汉斯的建议解决了这个问题。这里的解决方案有点长,但我很乐意通过电子邮件发送给任何要求的人。

毫无疑问,有几种方法可以做到,但我将一个LocationList指针传递给C#DLL。 C ++等效结构在C#中定义(具有正确的偏移量)。然后可以通过C#中的指针访问LocationList的字段,指向位置结构和位置字段的指针。不是C#友好但不是太糟糕,而不是用C ++重写整个事情。我没有使用只创建本地副本的Marshal.PtrToStructure。

最终结果是我在C ++调用程序中嵌套了结构,并且可以在C#DLL中读取或修改任何数据。

0 个答案:

没有答案