Маршалинг массива IntPtrs в C # - PullRequest
2 голосов
/ 07 апреля 2010

Из безопасного управляемого кода в C # я хотел бы вызвать функцию в C API, которая получает массив указателей (void **).

У меня есть соответствующий управляемый массив объектов IntPtr,но методы Маршала, объявленные в документации на MSDN, кажутся недостаточными для предоставления IntPtr неуправляемому блоку памяти с правильным содержимым.

Я надеялся получить IntPtr с помощью Marshal.AllocHGlobal, а затемназначьте правильный контент, используя Marshal.Copy, но, похоже, функция не была перегружена для массива IntPtr.

Есть мысли о том, как это сделать лучше?

Спасибо завперед.

Ответы [ 2 ]

4 голосов
/ 07 апреля 2010

Маршаллер P / Invoke уже делает это, вам не нужно помогать. Просто объявите аргумент функции как массив:

[DllImport("blah.dll")]
private static extern void SomeFunction(IntPtr[] array);

На всякий случай: хотя здесь не нужно использовать ключевое слово unsafe, в этом нет ничего безопасного. Код C может легко повредить кучу, когда записывает после конца выделенного вами блока.

3 голосов
/ 07 апреля 2010

Передайте массив как 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++);
}
}
...