我开始挣扎于这个问题。我已经搜索过并寻找过帮助,而我所尝试过的一切似乎都无法发挥作用。我显然做错了什么。
无论如何 - 我将c#结构定义为:
public struct TestStruct
[StructLayout(LayoutKind.Sequential)]
{
public int num;
public IntPtr intArrayPtr;
}
在我的c#代码主体中我有:
public class Testing
{
[DllImport("testing.dll")]
static extern void Dll_TestArray(out IntPtr intArrayPtr);
public GetArray()
{
IntPtr structPtr = IntPtr.Zero;
TestStruct testStruct;
structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(testStruct));
Marshal.StructureToPtr(testStruct, structPtr, false);
Dll_TestArray(structPtr);
testStruct = (TestStruct) Marshal.PtrToStructure(structPtr, typeof(TestStruct));
}
}
现在对于c ++部分。从结构开始:
struct TestStruct
{
public:
int num;
int* intArray;
}
现在功能:
extern "C" __declspec(dllexport) void Dll_TestArray(TestStruct *&testStruct)
{
int num = 15;
testStruct->num = num;
testStruct->intArray = new int[num];
for (int i = 0; i < num; i++)
testStruct->intArray[i] = i+1;
}
所以 - 我遇到的问题是,当我将结构重新放回c#时,我的结构不是它应该如何。我可以看到num字段已正确填充:它显示15.但是,IntPtr仍然设置为零。用c ++完成的数组创建还没有进行到c#。
如果我尝试退一步,然后返回到dll函数,我可以看到数组已创建好并仍然保留信息。
所以struct中的c#intptr没有被设置为在c ++中创建的指针(如果这是有意义的)。
所以我的问题是 - 如何使这项工作正确?
我希望能够从dll返回,这是一个包含我需要的所有信息的结构。也就是说,在这个例子中,元素的数量和指向数组的指针。这样,我就可以在intptr上做一个Marshal.Copy来获取数组。
如果有其他方法可以做到这一点,我非常乐意这样做。我已经尝试过几种方法,但无济于事。这包括在c#中尝试以下结构(其中包含int数组,而不是intptr):
public struct TestStruct
{
public int num;
// i have tried various methods to marshal this- eg:
// [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_I4]
public int[] intArray;
}
我也试过通过引用传递结构,而不是intptr。 任何有关此事的帮助都将受到大力赞赏。我无法更改c ++代码,但可以更改c#代码。
答案 0 :(得分:1)
首先,将C ++代码更改为仅使用一个间接级别:
extern "C" __declspec(dllexport) void Dll_TestArray(TestStruct &testStruct)
{
const int num = 15;
testStruct.num = num;
testStruct.intArray = new int[num];
for (int i=0; i<num; i++)
testStruct.intArray[i] = i+1;
}
在C#方面你想要这个:
public struct TestStruct
{
public int num;
public IntPtr intArray;
}
[DllImport("testing.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void Dll_TestArray(out TestStruct testStruct);
public GetArray()
{
TestStruct testStruct;
Dll_TestArray(out testStruct);
int[] arr = new int[testStruct.num];
Marshal.Copy(testStruct.intArray, arr, 0, arr.Length);
// need to call back to DLL to ask it to deallocate testStruct.intArray
}
您还需要导出一个函数,该函数将释放您使用C ++堆分配的数组。否则你会泄漏它。
也许更简单的方法是更改设计以让调用者分配缓冲区。