Member 14150748 Ответов: 1

Как маршалировать структуру с указателем на другую структуру (от C++ до C#)


Приветствую вас!

Как говорит титтл, мне нужно маршалировать структуру внутри указателя на другую структуру (на самом деле, вектор на другую структуру). Этот человек получает после определенного сообщения (связанный вопрос здесь), с его адрес как параметр lparam.

Это определение находится в а .dll-файл, сделанный третьей стороной (не имеет исходного кода), сделанный на C++. Вот вам пример:

typedef struct _cImage
{
  BYTE *Buffer;
  int Lenght;
} cImage;

typedef struct _Images
{
  DWORD DocID;
  cImage *Imgs;
  BOOL Enabled;
} Images;


Согласно инструкции...
Цитата:
Это указатель на вектор структуры cImage: 5 элементов для изображений и 10 для фрагментов.


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

Сначала я попытался определить структуру внутри внутреннего массива:

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct cImage
{
    public IntPtr Buffer;
    public int Lenght;
};

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct Images
{
    public int DocID;
    [MarshalAs(UnmanagedType.ByValArray)]
    public cImage[] Imgs;
    [MarshalAs(UnmanagedType.Bool)]
    public bool Enabled;
};


Вот как я пытаюсь извлечь эту информацию (она находится в классе "ScanMgr")

public bool getImage(IntPtr imgPtr, out Images img)
{
    try
    {
        img = (Images)Marshal.PtrToStructure(imgPtr, typeof(Images));
        return true;
    }
    catch { img = new Images(); }
    return false;
}


И вот здесь я вызываю функцию (сканер - это объект ScanMgr):

switch ((int)msg.WParam)
{
    /* Other cases */
    case (int)WMPAR.ImagesReady:
    Images img;
    if (scanner.getImage(m.LParam, out img))
        /* Here I should get access and use the struct members */
    break;
}


Затем я попытался заменить массив IntPtr на внутреннюю структуру, чтобы маршалировать его позже:

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct Images
{
    public int DocID;
    public IntPtr Imgs;
    [MarshalAs(UnmanagedType.Bool)]
    public bool Enabled;
};

////////////

switch ((int)msg.WParam)
{
    /* Other cases */
    case (int)WMPAR.ImagesReady:
    Images img;
    if (scanner.getImage(m.LParam, out img))
    {
        cImage cImg = (cImage)Marshal.PtrToStructure(img.Imgs, typeof(cImage));
        /* Access/Use the struct members */
    }
    break;
}


Мой вопрос таков: как правильно выстроить этот внутренний вектор структур? Если это IntPtr, то как я могу извлечь эти члены? (поскольку я просто буду работать с изображениями, я буду придерживаться вектора 5)

Заранее спасибо

1 Ответов

Рейтинг:
4

Member 14150748

Решаю все сам (Ага, я же библиотечная мышь!)


Я определил указатель на вектор как IntPtr (см. 2-ю реализацию структуры C# в предыдущем посте). Затем:

switch ((int)msg.WParam)
{
    /* Other cases */
    case (int)WMPAR.ImagesReady:
    Images img;
    if (scanner.getImage(m.LParam, out img))
    {
        var size = Marshal.SizeOf(typeof(cImage));
        cImage[] ar = new cImage[5];

        for (int i = 0; i < 5; i++)
        {
            IntPtr p = new IntPtr(img.Imgs.ToInt32() + i * size);
            ar[i] = (cImage)Marshal.PtrToStructure(p, typeof(cImage));
            logInfo.Items.Add(ar[i].Buffer + "-" + ar[i].Lenght);
        }
    }
    break;
}