我正在尝试将结构数组从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 ++方面,数组似乎已正确填充。(通过调试验证)。
答案 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