C ++ <-> C # изменить маршаллированный массив байтов - PullRequest
1 голос
/ 10 августа 2011

У меня есть неуправляемая функция C ++, которая вызывает управляемый метод C # в DLL.Цель метода C # состоит в том, чтобы взять массив байтов (выделенных вызывающей стороной C ++), заполнить массив и вернуть его.Я могу получить массив INTO метод C #, но заполненные данные теряются, когда они возвращаются к функции C ++.Прямо сейчас это мой тестовый код для отладки процесса:

C # DLL метод:

// Take an array of bytes and modify it
public ushort GetBytesFromBlaster([MarshalAs(UnmanagedType.LPArray)] byte[] dataBytes)
{
    dataBytes[0] = (byte)'a';
    dataBytes[1] = (byte)'b';
    dataBytes[2] = (byte)'c';
    return 3;
}

C ++ функция, которая вызывает DLL:

// bytes[] has been already allocated by its caller
short int SimGetBytesP2P(unsigned char bytes[])
{
    unsigned short int numBytes = 0;
    bytes[0] = 'x';
    bytes[1] = 'y';
    bytes[2] = 'z';
    // bytes[] are {'x', 'y', 'z'} here
    guiPtr->GetBytesFromBlaster(bytes, &numBytes);
    // bytes[] SHOULD be {'a', 'b', 'c'} here, but they are still {'x', 'y', 'z'}
    return(numBytes);

}

Я полагаю, что это как-то связано с тем, что C # превращает указатель C ++ в новый управляемый массив, но изменяет исходный.Я пробовал несколько вариантов, используя модификатор "ref" и т. Д., Но не повезло.Кроме того, эти данные НЕ являются строками с нулевым символом в конце;байты даты представляют собой необработанные 1-байтовые значения, не заканчивающиеся нулем.

Может кто-нибудь пролить свет на это?Спасибо!

Стюарт

Ответы [ 2 ]

4 голосов
/ 10 августа 2011

Вы могли бы сделать маршалинг самостоятельно.Пусть функция C # принимает параметр по значению типа IntPtr.Также второй параметр, указывающий длину массива.Никаких специальных атрибутов маршалинга не требуется или не требуется.

Затем используйте Marshal.Copy и скопируйте массив из неуправляемого указателя в выделенный вами массив управляемого байта [].Сделайте свое дело, а затем, когда вы закончите, используйте Marshal.Copy, чтобы скопировать его обратно в неуправляемый массив C ++.

Эти конкретные перегрузки должны помочь вам начать:

http://msdn.microsoft.com/en-us/library/ms146625.aspx
http://msdn.microsoft.com/en-us/library/ms146631.aspx

Например:

public ushort GetBytesFromBlaster(IntPtr dataBytes, int arraySize)
{
    byte[] managed = new byte[arraySize];
    Marshal.Copy(dataBytes, managed, 0, arraySize);
    managed[0] = (byte)'a';
    managed[1] = (byte)'b';
    managed[2] = (byte)'c';
    Marshal.Copy(managed, 0, dataBytes, arraySize);
    return 3;
}

В качестве альтернативы вы можете реализовать собственный маршаллер, как описано в http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx, если по умолчанию не выполняетсячто вам нужно.Но это похоже на большую работу.

0 голосов
/ 11 августа 2011

Я считаю, что вам просто нужно добавить атрибут SizeConst:

public ushort GetBytesFromBlaster(
    [MarshalAs(UnmanagedType.LPArray, SizeConst=3)] 
    byte[] dataBytes
)

, и маршаллер по умолчанию должен сделать все остальное за вас.

...