将结构数组从C ++(COM)传递给C#

时间:2011-11-06 20:57:31

标签: c# c++ com interop

我正在尝试将结构数组从C ++(COM)传递给C#

        //C++ definition
        //MyStruct being a COM Visible Structure 
        HRESULT GetArrofStruct([in,out] LONG* count, [out,size_is(,*pnCnt)] MyStruct** ppArr);

        //C# definition
        void GetArrofStruct(ref int Count,out IntPtr outPtr);

        //I use the Function Something like this in C#

        IntPtr buffer = IntPtr.Zero;

        int Count;

        GetArrofStruct(ref Count,out buffer);
        MyStruct[] arrayManaged = new MyStruct[Count];

        for (int i = 0, nElemOffs = (int)buffer; i < Count; i++)
        {
            ru[i] = (MyStruct)Marshal.PtrToStructure((IntPtr)nElemOffs, typeof(MyStruct));
            nElemOffs += Marshal.SizeOf(typeof(MyStruct));
        }  

在for循环中,第一个元素被正确编组,对于第二个元素,我得到一个AccessViolation。

在C ++方面,数组似乎已正确填充。(通过调试验证)。

2 个答案:

答案 0 :(得分:0)

您正在使用指针指针,因此您只需要通过指针的大小增加偏移量(nElemOffs),而不是结构的大小并取消引用它。

说明:

您在C ++端使用MyStruct**而不是MyStruct*,这意味着您需要在将指针值转换为结构之前取消引用它。

示例代码:

int Count;
IntPtr pBuffer;

GetArrofStruct(ref Count,out pBuffer);
MyStruct[] arrayManaged = new MyStruct[Count];
unsafe
{
    Int32 buffer = (int)pBuffer;

    for (int i = 0; i < Count; i++)
    {
        // Read the memory position of the structure
        Int32 p = *((Int32*)buffer);
        arrayManaged[i] = (MyStruct)Marshal.PtrToStructure((IntPtr)p, typeof(MyStruct));

        buffer += 4; // increase by pointer size
    }  
}

小方注:

确保您的结构MyStruct在C#和C ++方面具有相同的大小,[StructLayout(..)]可能会有所帮助。

答案 1 :(得分:0)

嗯,问题在于(int)缓冲区强制转换。运算符+在int和IntPtr上是不同的。请看以下内容:

   for (int i = 0; i < Count; i++)
   {
      IntPtr newPtr = buffer + i * sizeof(typeof(MyStruct));
      ru[i] = (MyStruct)Marshal.PtrToStructure(newPtr, typeof(MyStruct));
   } 

我没有测试过这个,我不知道你的IntPtr的内容是否正确并且是否正确分配,但这是你应该如何遍历结构数组。

至于编组问题,编组是由IDL定义的,所以请检查你的数组定义。我不确定([out]数组总是让我感到困惑),但在我看来,你有一个太多的维度。尝试以下(如果一个是正确的,请告诉我):

[out,size_is(pnCnt)] MyStruct** ppArr

[out,size_is(*pnCnt)] MyStruct* ppArr