Marshalling C struct, содержащий массивы для С#

С большой помощью сообщества stackoverflow мне удалось вызвать собственную DLL-функцию. Однако я не могу изменить значения массива ID или intersects. Независимо от того, что я делаю с ним на стороне DLL, старое значение остается. Он доступен только для чтения.

Вот некоторые фрагменты кода:

С++ struct:

typedef struct _Face {
    int ID;
    int intersects[625];
} Face;

Отображение С#:

[StructLayout(LayoutKind.Sequential)]
    public struct Face {
        public int ID;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 625)]
        public int[] intersects;
    }

Метод С++ (тип установлен в DLL в VS2010):

extern "C" int __declspec(dllexport) __stdcall 
solve(Face *faces, int n){
for(int i =0; i<n; i++){
    for(int r=0; r<625; r++){
        faces[i].intersects[r] = 333;
        faces[i].ID = 666;
        }
    }

Подпись метода С#:

[DllImport("lib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int solve(Face[] faces, int len);

Вызов метода С#:

Face[] faces = new Face[10];
faces[0].intersects = new int[625];
faces[0].ID = -1; //.. and add 9 more ..

solve(faces, faces.Length);

// faces[0].ID still equals -1 and not 666

С наилучшими пожеланиями, е.

Ответ 1

Вы должны явно указать маркеру pinvoke, что массив должен быть перенаправлен обратно. Вы делаете это с атрибутами [In] и [Out]. Вот так:

    [DllImport("...")]
    public static extern int solve([In, Out] Face[] faces, int len);

Ответ 2

Это только поле вывода? Чтобы понять это, я бы попытался заменить ваш параметр Face [] на достаточно большой байт [] и посмотреть, заполняется ли массив байтов чем-либо (вам придется немного изменить ваш [DllExport]).

Кроме того, еще одна вещь, которую я использовал, когда делаю это с помощью char *, - это то, что мне пришлось предварительно выделить буфер на С#. Например:

StringBuilder theString=new StringBuilder();
MyUnmanagedFunction(theString);

не будет работать. Но если предположить, что вернувшаяся строка была макс. 256 символов, я бы сделал следующее:

StringBuilder theString=new StringBuilder(256);
MyUnmanagedFunction(theString);

И я буду в бизнесе. Я бы рекомендовал попробовать подстановку byte [], если это не работает, попробуйте предварительно выделенный массив байтов. Как только вы видите, что массив байтов действительно изменяется на ваш код на С++, вы можете выяснить, как маршалировать эту вещь в своей структуре С#.