Как создать оболочку C ++ \ Cli для неуправляемых C DLL

0

Я, наверное, смущаюсь, но раньше этого не делал, и немного было бы очень полезно.
Я пытаюсь вызвать код C из приложения C#. Я попытался использовать PInvoke но PInvoke что это немного сложно. Я думал, что попробую сделать C++\CLI.

Существуют несколько сложных структур, которые имеют двойные массивы переменной длины, с которыми трудно было справиться с PInvoke.
Я читал немного о том, как это делается, но я не могу понять это. Большая часть того, что я нашел, относится к обертке C++ вместо C C код уже экспортирует свои функции, которые работают уже с Java-приложения и его службы JNA. У меня есть C код, заголовки, библиотека и dll, но скорее бы не вносил изменений ни в что существующее, чтобы не нарушать другие потребляющие приложения. Приложение C# вызывающее его, будет 64-битным, большинство примеров создадут библиотеки win32, не так ли?

UPDATE: добавление кода ниже:
ПРИМЕЧАНИЕ. Это всего лишь одна функция нескольких и, возможно, самая простая, но все они довольно схожи.

C HEADER:
typedef struct myStruct_t
{
    double prefix[8];
    int length;
    double array[1];
}
myStruct;

C:
extern "C" __declspec( dllexport ) myStruct *doSomething(const myStruct *input, double a)
{
    myStruct *output;
    //doSomething
    return output;
}
  • 0
    Win32 - это общее имя для Windows API в 32- и 64-разрядных версиях Windows. Если приложение C # является 64-разрядным, то используемая вами библиотека DLL должна быть 64-разрядной. Это?
  • 0
    c dll 64-битный, win32-бит dll-оболочки c ++ \ cli заставил меня думать, что это 32-битный
Теги:
c++-cli

3 ответа

1

Если Java может вызывать ваш код C через jna, тогда не должно быть проблем с С# через PInvoke. В то время как C++ interop (с использованием C++/Cli) является одним из типов PInvoke (Implicit PInvoke), использование DllImport является явным PInvoke.

Неявный PInvoke полезен, когда вам не нужно указывать, как будут параметризованы параметры функции, или любую другую информацию, которая может быть указана при явном вызове DllImportAttribute, но вам понадобится добавить дополнительную C++/CLI Dll.

В обоих случаях вам приходится иметь дело с собственными типами данных маршала для управляемых, это неизбежно и болезненно.

в С#, структура может быть объявлена как:

[StructLayout(LayoutKind.Sequential)]
    public struct myStruct {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        double prefix[] intersects;

        public int length;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public double[] array;
    }

Но для этой функции DLLImport не может справиться с этим случаем, потому что С# не может удалить память для неуправляемого указателя, возвращаемого функцией, вы можете создать еще одну функцию переноса в C, чтобы она использовала параметр out для возврата результата, в этом случае код С#:

[DllImport("...")]
    public static extern void doSomething([In, Out] myStruct[] results,  myStruct[] input,  int len);

Или вы можете использовать C++/CLI interop, так как он может обрабатывать как собственные, так и управляющие типы, поэтому вызывающая последовательность:

  1. Код С# вызывает эту функцию C++/CLI с управляемыми типами данных:

    ManagedmyStruct [] doSomething (ManagedmyStruct [] input, double a)

  2. В функции C++/CLI domSomething она вызывает функцию native, этапы:

    ManagedmyStruct [] doSomething (ManagedmyStruct [] input, double a) {

      //convert the ManagedmyStruct[] input to native type myStruct* input
      myStruct ret* =  doSomething(input, a);
      //convert ret to managed type ManagedmyStruct[] rets
      return rets;
    

    }

  • 0
    добавили код выше, в основном интересно, как работать со структурой, содержащей массивы переменной длины, размер 1 будет переменной длины
  • 0
    Массив длины 1 в качестве последнего члена структуры, содержащей int var с именем name, является довольно четким признаком взлома структуры C. Так что никакое количество маршаллинга структуры pinvoke не сделает это. Вам нужно ручное ведение IntPtr.
1

Там действительно очень мало различий между оберткой C и C++. Вам необходимо создать библиотеку классов C++/CLI. Затем вы записываете функции в управляемый класс C++ ref, который переносит собственный код.

Например, предположим, что DLL экспортирует эту функцию:

int sqr(int x)

Затем в вашей библиотеке классов вы включите заголовочный файл:

#include <mynativelibrary.h>

Вам также необходимо предоставить библиотеку импорта в компоновщик.

Затем вы можете открыть функцию. Самый простой способ - обернуть функции как статические методы класса ref. Например:

public ref class Class1
{
public:
    static int sqr(int x)
    {
        return ::sqr(x);
    }
};

Затем вы можете использовать эту сборку в своем коде С#, как и в любой другой сборке.

  • 0
    спасибо плохо попробую это. Что делать, если функция с принимает структуру и возвращает структуру. Как это обрабатывается в оболочке C ++?
  • 0
    сама функция не определена в заголовке. только структуры, макросы и т. д. это имеет значение?
Показать ещё 7 комментариев
1

Я создал несколько проектов в VisualStudio 2012, которые обертывают старую MFC-библиотеку с управляемым кодом. Я сделал это так:

  1. Создайте библиотеку классов как CLR.
  2. Свяжите старый проект с этим новым проектом
  3. Создайте обертки в новом проекте для функций и структур и вызовите старый код.
  4. Используйте новый объект в коде С#.

Не забудьте создать Unittesting для управляемого кода C++. (Я всегда забываю... :))

Удачи.

  • 0
    можешь пожалуйста! более подробно, я новичок в Visual C ++, а также сталкиваюсь с той же проблемой
  • 0
    @ Ka7lm1011 Пожалуйста, посмотрите на это: c-sharpcorner.com/UploadFile/SamTomato/…

Ещё вопросы

Сообщество Overcoder
Наверх
Меню