Вопрос

У меня есть авторитетный код стандарта C ANSI.Это означает, что, хотя у меня есть исходный код, я не могу ни переводить его на другой язык, ни изменять вызывающие аргументы, поскольку такие действия лишат законной силы полномочия.Имеется более 150 функций.

Я могу внести случайные изменения, например изменить имена файлов с .C на .CPP, чтобы они компилировались с использованием компилятора C++ Visual Studio 2009, что я и сделал.Также можно добавить директивы компилятора и тому подобное.При необходимости я также могу пройти слой обертки.

Еще одно ограничение: моя компания делает нет хочу, чтобы я использовал небезопасный ключевое слово в любом коде C#.

Мне нужно получить доступ к этим функциям из программы на C#.

Типичная функция C/C++ выглядит так:
double SomeFunction(double a, double[3] vec, double[3][3] mat);
Где содержимое массива иногда вводится, иногда выводится, а редко и то, и другое.

Сначала я попробовал создать неуправляемую DLL (с ​​функциями, отмеченными Extern C).Функции только с простыми аргументами (int, double) работали нормально, но я не мог определить, как маршалировать массивы.(На самом деле я нашел несколько примеров кода, но его было чрезвычайно сложно и нецелесообразно дублировать 150 раз.)

Затем я попробовал два проекта в рамках одного решения: один на C++, другой на C#.В проекте C++ я создал управляемую функцию, которая просто вызывала исходную функцию, помеченную как неуправляемая.Это было чрезвычайно ясно и просто, и опять же, простые аргументы работали нормально.Но для массивов я не смог найти, как обеспечить совпадение типов аргументов на границе C# и C++:
Аргумент «2»:невозможно преобразовать из «double[]» в «double*»
(и, как упоминалось выше, я не могу использовать unsafe для получения указателя).

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

Это было полезно?

Решение

Пример реализации C/C++:

extern "C" __declspec(dllexport)
double SomeFunction(double a, double vec[3], double mat[3][3]) {
  double sum = a;
  for (int ix = 0; ix < 3; ++ix) {
    sum += vec[ix];
    for (int iy = 0; iy < 3; ++iy) {
      sum += mat[ix][iy];
    }
  }
  return sum;
}

Пример использования C#:

private void Form1_Load(object sender, EventArgs e) {
  double[] vec = new double[3];
  double[,] mat = new double[3, 3];
  for (int ix = 0; ix < 3; ++ix) {
    vec[ix] = ix;
    for (int iy = 0; iy < 3; ++iy) {
      mat[ix, iy] = (ix + 1) * iy;
    }
  }
  double sum = SomeFunction(1, vec, mat);
}
[System.Runtime.InteropServices.DllImport("cpptemp8.dll")]
private static extern double SomeFunction(double a, double[] vec, double[,] mat);

Другие советы

Если вы не можете заставить работать решение extern и P/Invoke, лучшим выбором, вероятно, будет оболочка.Создайте управляемую C++ DLL, которая использует как управляемый, так и неуправляемый код.Добавьте в эту DLL класс .NET, который представляет собой лишь тонкую оболочку функций в вашей C DLL.Ваш код C# может вызывать класс C++ .NET, который, в свою очередь, будет выполнять функции C.

Таким образом, вы можете самостоятельно написать перевод между .NET и неуправляемым кодом, не полагаясь на то, что среда выполнения сделает это за вас.

используйте swig, он сгенерирует для вас ваш pinvoke

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top