Передача Int массива из C# в Dll на C++

130
14 марта 2021, 07:50

Пытаюсь передать массив Int из C# в C++. Выскакивает ошибка:

Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

[DllImport("FindProject.dll", CharSet = CharSet.Unicode)]
public static extern bool Find(int count, [In, Out] int[] first_v, [In, Out] int[] second_v);

int[] fv = new int[Convert.ToInt32(count_rec)];
int[] sv = new int[Convert.ToInt32(count_rec)];
sqlExpression = "SELECT FIRST_VERTEX, SECOND_VERTEX FROM Edges";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    SqlCommand command = new SqlCommand(sqlExpression, connection);
    SqlDataReader reader = command.ExecuteReader();
    if (reader.HasRows) // проверка на наличие данных
    {
        int i = 0;
        while (reader.Read())
        {
            int id_FVvertex = reader.GetInt32(0);
            int id_SVvertex = reader.GetInt32(1);
            fv[i] = id_FVvertex;
            sv[i] = id_SVvertex;
            i++;
        }
        Find(Convert.ToInt32(count_rec), fv, sv);
    }
}

Данные для массива я получаю из заброса к базе данных. Если явно указывать константное значение для элементов массива, то все работает. Подскажите, как исправить данную проблему?

Строка объявления функции в Dll:

extern "C" _declspec(dllexport) bool __stdcall Find(int count, int *first_v, int *second_v)
Answer 1

В комментарий не влезает моё сообщение, напишу ответом.

Так как строки при интеропе не используются, параметр CharSet не нужен. Хотя он ничего и не портит.

Соглашение о вызове по умолчанию равно CallingConvention.StdCall - можно не добавлять.

Возвращаемый тип bool нужно маршалировать с указанием следующего атрибута:

[return: MarshalAs(UnmanagedType.Bool)]

Массивы следует помечать атрибутом

[MarshalAs(UnmanagedType.LPArray)]

В итоге, объявление функции может выглядеть так:

[DllImport("FindProject.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Find(
    int count,
    [MarshalAs(UnmanagedType.LPArray), In, Out] int[] first_v,
    [MarshalAs(UnmanagedType.LPArray), In, Out] int[] second_v
);

Я не уверен, нужно ли массив преобразовывать в указатель типа IntPtr. Вроде бы маршалер, когда встречает int[], сам это делает.

Answer 2

У вас fv - используется чисто на запись, и нигде на чтение. Вероятнее всего GC его во время вызова - просто убирает как мусор, считая что далее массив не используется (константные значения хранятся в отдельном месте памяти, и их уборщик не убирает). Самым простым решением будет сказать уборщику, что массив вам нужен, до вызова Find (лучше сразу после new)

GC.KeepAlive(fv);
GC.KeepAlive(sv); 

Чуть по сложнее, можно создать ссылку на массив, состояние ссылки Pinned (в англ pining называется) не даёт среде уничтожить обьект.

GCHandle myArrayHandle1 = GCHandle.Alloc(fv,GCHandleType.Pinned);
GCHandle myArrayHandle2 = GCHandle.Alloc(sv,GCHandleType.Pinned);
Find(Convert.ToInt32(count_rec), fv, sv);
myArrayHandle1.Free();
myArrayHandle2.Free();

Ранее тут был пост

Можно попробовать вариант с открытыми адресами... и дизассемблером на моменте ошибки проследить ссылки.

Обьявим ф-цию

[DllImport("FindProject.dll")]
public static extern bool Find(int count, IntPtr first_v, IntPtr second_v);

А вызов будет через маршалинг, таким

Find(Convert.ToInt32(count_rec),
     Marshal.UnsafeAddrOfPinnedArrayElement(fv,0),
     Marshal.UnsafeAddrOfPinnedArrayElement(sv,0));

До сих пор я считал что с# не умеет передавать масивы в с++. Код верный.

READ ALSO
TrimmingText для TextBlock с MultiBinding

TrimmingText для TextBlock с MultiBinding

Не получается решить проблемуУ меня есть TextBlock, который показывает имя файла и расширение

107
c# excel interop. Отчет по датам

c# excel interop. Отчет по датам

Интересует вопрос формирования отчета в ExcelИмеется база данных

118
ru_RU Оффлайновое распознавание речи (SpeechToText)

ru_RU Оффлайновое распознавание речи (SpeechToText)

Распознавание речи в оффлайне не работает с русским языком,но работает со всем остальнымиВсе словари скачаны

88