Получение неуправляемых функций C++ из C#
Вопрос
У меня есть авторитетный код стандарта 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