我有需要传递给外部方法的锯齿状数组。
[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);
...
fixed (ulong* ptr = array[0])
{
for (int i = 0; i < array.Length; i++)
{
fixed (ulong* p = &array[i][0])
{
ptrArray[i] = new IntPtr(p);
}
}
NativeMethod(ptrArray);
}
问题是ptr未使用,因编译而被删除。根据它的固定声明也被删除。所以数组被GC移动,使得ptrArray元素变为无效。
将锯齿状数组作为指向本机方法的指针的一维数组传递的最佳方法是什么?
更新:
以下是NativeMethod的C ++代码:
NativeClass::NativeMethod(const int* array)
答案 0 :(得分:3)
你的问题在于你需要修复数组,因为那是你正在使用的数组。您可以固定阵列,以便GC不收集它:
GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);
<强>更新强>
正如您正确指出的那样,数组中的每个数组也需要固定。
答案 1 :(得分:0)
我已经能够通过外部Pinvoke方法将C#锯齿状数组传递给C ++,而不使用不安全的C#代码,如下面的代码示例所示。但我仍然担心在非调试模式下GC会导致副作用不良的副作用。这是测试代码(在调试模式下工作):
[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
var jaggedArray = new int[3][];
jaggedArray[0] = new int[1] { 9 };
jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
jaggedArray[2] = new int[2] { 1, 2 };
//GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned); //This does not work
var pinnedHandles = new GCHandle[3];
var jaggedArrayPtrs = new IntPtr[3];
for (int i = 0; i < 3; i++)
{
pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
}
var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);
Console.WriteLine(result); //returns 8 as it should.
//mainHandle.Free();
for (int i = 0; i < 3; i++)
{
pinnedHandles[i].Free();
}
}
//The C++ test method:
extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray)
{
return jaggedArray[1][3];
}
如果我要取消注释mainHandle部分,我会得到一个参数异常“Object包含非原始数据或非blittable数据”。 那么是否可以固定jaggedArray并且它真的需要吗?(我模糊地回想一下,如果不再使用GC,在发布模式下GC可能会重新收集方法中的内存。)我认为相反,将jaggedArray放入类字段变量可以使其从GC角度安全。