Praveen Kumar Katiyar Ответов: 1

Как маршалировать структурный массив с помощью intptr.


У меня есть следующий код в библиотеке DLL C++

typedef struct _MYPOINT
{
    int nX;
    int nY;
} MYPOINT;
 
extern "C"  __declspec(dllexport) void ModifyPointArray (int nSize, MYPOINT *ptArr[]) 
{ 
    for ( int nI = 0; nI < nSize; nI++ )
    {
	ptArr[nI]->nX +=5;
	ptArr[nI]->nY +=5;
    }
}


======================================

Я определил класс-оболочку для DLL примерно так.

namespace MarshalDemo
{
    [StructLayout(LayoutKind.Sequential)]
    public class MyPoint
    {
        public int nX;
        public int nY;
        
        public MyPoint()
        {
            this.nX = 0;
            this.nY = 0;
        }
        public MyPoint(int x, int y)
        {
            this.nX = x;
            this.nY = y;
        }
    }
   
    public static class MarshalDllWrapper
    {
     
      [DllImport("MarshalDll.dll")]
      public static extern void ModifyPointArray(int nSize, IntPtr [] arrPts);
    }
}


Что я уже пробовал:

Теперь я пытаюсь вызвать эту функцию с помощью маршалинга с помощью IntPtr, мой клиентский код .NET (C#) выглядит примерно так.

MyPoint[] pointArr = { new MyPoint(5, 6), new MyPoint(7, 8), new MyPoint(9, 10) };
int nCount = pointArr.Length;
IntPtr[] ptrArr = new IntPtr[nCount];
for (int nI=0; nI< nCount; nI++)
{
     ptrArr[nI] = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(MyPoint)));
     Marshal.StructureToPtr(pointArr[nI], ptrArr[nI], true);
}

MarshalDllWrapper.DisplayPointArray(nCount, ptrArr);
MyPoint[] pointArr2 = new MyPoint[nCount];
for (int nI = 0; nI < nCount; nI++)
{
     Marshal.PtrToStructure(ptrArr[nI], pointArr2[nI]);
     Marshal.FreeCoTaskMem(ptrArr[nI]);
}


Я получаю ошибку на линии
//F:\VS2010\VCS2010\Marshalling\MarshalDll\MarshalDllClient\frmMarshalDemo.cs:line ХХХ
Marshal.PtrToStructure(ptrArr[nI], pointArr2[nI]);


с сообщением об ошибке

Система.ArgumentNullException: значение не может быть null.
Имя параметра: структура
в System.Runtime.InteropServices.Маршал.PtrToStructureHelper(IntPtr ptr, Object structure, Boolean allowValueClasses)
в System.Runtime.InteropServices.Маршал.PtrToStructure(IntPtr ptr, структура объекта)
в MarshalDemo.frmMarshalDemo.btnPointArray_Click(отправитель объекта, EventArgs e) в F:\VS2010\VCS2010\Marshalling\MarshalDll\MarshalDllClient\frmMarshalDemo.cs:line 150


PS : Я знаю, если я напишу обертку что-то вроде этого.
public static extern void ModifyPointStructArray(int nSize, [In, Out] MyPoint[] arrstruct);

это работает как ветер, но я хочу сделать с IntPtr, я делаю что-то концептуально неправильное ?

Что я делаю не так ?
Любая помощь будет оценена по достоинству.

Спасибо.

Правин.

1 Ответов

Рейтинг:
10

Richard Deeming

structure: Объект, на который должны быть скопированы данные. Это должен быть экземпляр отформатированного класса.
Вы создали новый массив MyPoint- но вы еще не инициализировали его. Таким образом, каждый слот в массиве является null- и ты пытаешься пройти мимо null в structure параметр.

Инициализируйте значение перед его передачей:
MyPoint[] pointArr2 = new MyPoint[nCount];
for (int nI = 0; nI < nCount; nI++)
{
    pointArr2[nI] = new MyPoint();
    Marshal.PtrToStructure(ptrArr[nI], pointArr2[nI]);
    Marshal.FreeCoTaskMem(ptrArr[nI]);
}


Praveen Kumar Katiyar

Ты спасла мне жизнь, какая глупая ошибка.

Большое спасибо.