使用IntPtr将结构数组从C#传递给C ++

时间:2013-09-13 08:11:51

标签: c# c++ pinvoke

我有一个结构 - >

   public struct readers
   {
       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
       public IntPtr[] tag_list;
   };

编组必须在“IntPtr [] tag_list”&之间进行。结构TAG_IN_PARAM

   [StructLayout(LayoutKind.Sequential)]
   internal struct TAG_IN_PARAM
   {
       public int vis_cnt;
       public bool valid;
   }

它的数组为=> TAG_IN_PARAM [] tag_list = new TAG_IN_PARAM [1000];

我想将结构“读者”从C#传递给C ++ DLL。但是,我一直在进行编组,但垃圾值正在DLL端。

//分配内存 Marshal.StructureToPtr(tag_list [j],Reader.tag_list [j],false);

或者如果我能做任何其他方式,请输送。 任何帮助,将不胜感激。 在此先感谢。

1 个答案:

答案 0 :(得分:0)

您要匹配的C ++类型是,根据您的评论:

class Readers 
{
public:
    TAG_IN_PARAM* tag_list;
};

这是一个指向数组的指针。

但是你的C#代码声明了一个内联数组。您的C#代码将与此匹配:

class Readers 
{
public:
    TAG_IN_PARAM tag_list[1000];
};

显然,这不是你想要的方式。

您需要更改C#代码才能使其匹配。不幸的是,当数组在结构内时,marshaller似乎不会将数组编组为指向第一个元素的指针。由于数组是结构中唯一的东西,因此您只需将数组作为参数传递即可。

或者,如果您绝对需要在结构中传递数组,那么我认为您需要手动编组。像这样。

public struct readers
{
    public IntPtr tag_list;
};

然后你可以简单地固定阵列。

TAG_IN_PARAM[] tag_list = ...;
GCHandle pinnedArray = GCHandle.Alloc(tag_list, GCHandleType.Pinned);
readers r;
r.tag_list = pinnedArray.AddrOfPinnedObject();
// call function passing r
pinnedArray.Free();

不幸的是,由于C#bool不是blittable,因此效果不佳。因此,您可以通过为该字段使用不同的类型来解决这个问题。例如byteint,具体取决于C ++方面的内容。

另一个选项是每个字段Marshal.StructureToPtr。这将是这样的:

TAG_IN_PARAM[] tag_list = ...;
int structSize = Marshal.SizeOf(typeof(TAG_IN_PARAM));
r.tag_list = Marshal.AllocHGlobal(tag_list.Length*structSize);
IntPtr ptr = r.tag_list;
for (int i = 0; i < tag_list.Length; i++)
{
    Marshal.StructureToPtr(tag_list[i], ptr, false);
    ptr += structSize;
    // or on older versions of .net without arithmetic support on IntPtr
    // ptr = (IntPtr) (long)ptr + structSize;
}
// call function passing r
Marshal.FreeHGlobal(r.tag_list);