从C#中安全的托管代码,我想调用一个接收指针数组的C API函数(void **)。
我有相应的IntPtr对象托管数组,但MSDN文档中公布的Marshal方法似乎不足以将IntPtr提供给具有正确内容的非托管内存块。
我曾希望获得一个带有'Marshal.AllocHGlobal'的IntPtr,然后使用'Marshal.Copy'分配正确的内容,但似乎函数没有为IntPtr数组重载。
有关最佳方法的任何想法吗?
提前致谢。
答案 0 :(得分:4)
P / Invoke marshaller已经这样做了,你没必要帮忙。只需将函数参数声明为数组:
[DllImport("blah.dll")]
private static extern void SomeFunction(IntPtr[] array);
以防万一:虽然你不必在这里使用unsafe关键字,但它没有任何安全性。当C代码写入超过您分配的块的末尾时,C代码很容易破坏堆。
答案 1 :(得分:3)
将数组作为IntPtr []传递,默认情况下,IntPtr被编组为void *。没有 需要不安全。
[DllImport("containingFoo.dll")]
public static extern void foo( IntPtr[] ptr);
...
// some floats
float[] fpa = {7.2F, 2.3F, 3.3F, 4.5F, 6.5F};
// allocate unmanaged for float[] fpa and int (length of array)
IntPtr fptr = Marshal.AllocHGlobal(fpa.Length *
Marshal.SizeOf(typeof(float)));
IntPtr iptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));
// set length of array
Marshal.WriteInt32(iptr, fpa.Length);
// copy the array
Marshal.Copy(fpa, 0, fptr, fpa.Length);
// strore both pointers in IntPtr[]
IntPtr[] pptr = {fptr, iptr};
// call foo passing the IntPtr[] to C
foo(pptr);
// C / C ++ //请注意,stdcall是使用时的默认调用约定 的PInvoke !!!!
void __stdcall foo(void** data)
{
float * fa = (float*)*data; // first element points to float array
int *ip = (int*)data + 1; // pointer to next element in void array
int *pp = (int*)*ip; // get pointer to int
for (int i = 0; i < *pp ; i++)
{
printf("\t: %f\n", *fa++);
}
}