Передача данных массива между C # и DLL (в обоих направлениях)

#c# #dllimport

#c# #dllimport

Вопрос:

У меня есть некоторый код на C, который компилируется в DLL. Из C # мне нужно передать ему массив целых чисел, и мне нужно получить из него массив целых чисел.

Вот что у меня есть на данный момент. В C # единственная функция, которая работает, — это bar(). Он возвращает 22 и записывает в файл, как и ожидалось. Другие записывают данные в свои файлы должным образом, но выдают исключение, когда управление возвращается C #. Он читает,

«Вызов функции PInvoke ‘irhax!irhax.App::foo’ привел к дисбалансу стека. Вероятно, это связано с тем, что управляемая подпись PInvoke не соответствует неуправляемой целевой подписи. Убедитесь, что соглашение о вызове и параметры подписи PInvoke соответствуют целевой неуправляемой подписи.»

C (библиотека DLL):

 #define IG_API __declspec(dllexport)

IG_API void foo(int i) {
    FILE *f = fopen("foo.txt", "a ");
    fprintf(f, "%dn", i);
    fclose(f);
}

IG_API int bar(void) {
    FILE *f = fopen("bar.txt", "a ");
    fprintf(f, "bar!n");
    fclose(f);
    return 22;
}


IG_API void transmitIR(unsigned *data, int length) {
    FILE *f = fopen("transmit.txt", "a ");
    for(int i = 0; i < length;   i)
        fprintf(f, "%d, ", data[i]);
    fprintf(f, "n");
    fclose(f);
}

IG_API int receiveIR(unsigned *data, int length) {
    for(int i = 0; i < length;   i)
        data[i] = 4;
    return length;
}
  

C # (вызывающий объект):

 [DllImport("Plugin.dll")]
static extern void foo(int i);

[DllImport("Plugin.dll")]
static extern int bar();

[DllImport("Plugin.dll")]
static extern void transmitIR(uint[] data, int length);

[DllImport("Plugin.dll")]
static extern int receiveIR(out uint[] data, int length);
  

Я в растерянности. Что я делаю не так? Поскольку я даже не могу заставить foo (int) работать, это кажется хорошим местом для начала.

Ответ №1:

Ваш код на C использует соглашение о вызове cdecl. Код C # использует stdcall.

Все DLLImport атрибуты должны быть:

 [DllImport("Plugin.dll", CallingConvention=CallingConvention.Cdecl)]
  

Конечно, вы могли бы альтернативно переключить код C на stdcall с помощью __stdcall . Но убедитесь, что вы выполняете только одно из этих действий!

receiveIR не требуется out . Вы должны объявить это:

 static extern int receiveIR(uint[] data, int length);
  

Ответ №2:

Знаете ли вы соглашение о вызове функций C? Как указано в ошибке, это, вероятно, несоответствие. Соглашение о вызове по умолчанию — stdcall, но если эти функции используют соглашение cdecl, вы, скорее всего, получите эту ошибку. Попробуйте

 [DllImport("Plugin.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void foo(int i);