Написание DLL на C / C ++ для взаимодействия .Net - PullRequest
12 голосов
/ 16 сентября 2010

В моем приложении на C # я хотел бы написать часть кода на C. Я планирую написать DLL-ведьму, которая была бы совместима с .Net.Как я могу это сделать?

Ответы [ 4 ]

20 голосов
/ 16 сентября 2010

Существуют три правильных способа сделать это:

  • Используйте C ++ / CLI. Это оптимальный способ, если эта DLL будет использоваться только .NET.
  • Используйте «extern "C"» совместимый API, например, сам Windows API. Это наиболее переносимый вариант, но он не так удобен для ваших абонентов, как использование модели классов для представления ваших объектов.
    • Это лучший вариант, если вы действительно хотите писать в ANSI C (не в C ++).
    • Для этого пути вы пишете свои функции как extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
    • Вам также следует использовать модель памяти "caller-Обеспечивает буфер", а не возвращать буфер, выделенный внутри вашей библиотеки. В тех случаях, когда вам необходимо выделить память для внутреннего состояния, вызывающая сторона должна рассматривать ее как непрозрачный дескриптор, и вы должны предоставить вызывающей функции функции доступа для извлечения данных. Ни при каких обстоятельствах вызывающая сторона не должна освобождать память, выделенную внутри вашей библиотеки, однако для вызывающей стороны можно попросить библиотеку выполнить освобождение.
  • Использовать COM или COM-подобный API. Здесь вы возвращаете (часто через параметр out) указатель на интерфейс, который является классом с чисто виртуальными функциями, без не виртуальных функций и без данных.
    • Реализация в конкретных классах, полученных из этого абстрактного интерфейса, они могут иметь множество функций данных и вспомогательных функций, поскольку это не влияет на двоичный интерфейс.
    • Это намного больше работы в библиотеке, но чрезвычайно портативное и простое в использовании для потребителя.

И совершенно НЕЛЬЗЯ делать одну вещь:

  • использовать __declspec(dllexport) в классах C ++.

РЕДАКТИРОВАТЬ: Я также хочу объяснить некоторые хорошие практики для варианта № 2, который увеличит переносимость и сделает нативные части C / C ++ пригодными для использования из неуправляемых приложений.

Вы можете сделать это проще с помощью макроса, обычный способ сделать это:

В вашем заголовочном файле все объявления функций выглядят как

MYPROJECTAPI(returntype) PublicFunc(params);

В вашем проекте определение

#define MYPROJECTAPI(returntype) \
                   extern "C" returntype __stdcall __declspec(dllexport)

В потребительских проектах

#define MYPROJECTAPI(returntype) \
                   extern "C" returntype __stdcall __declspec(dllimport)

и затем вы можете определить макрос по-другому для других компиляторов, таких как gcc, которые не используют __declspec.

Полное решение будет выглядеть (в общедоступном заголовочном файле myproject.h):

#if _WIN32
#  if BUILDMYPROJECT
#    define MYPROJECTAPI(returntype) \
         extern "C" returntype __stdcall __declspec(dllexport)
#  else
#    define MYPROJECTAPI(returntype) \
         extern "C" returntype __stdcall __declspec(dllimport)
#  endif
#else
#  define MYPROJECTAPI(returntype) extern "C" returntype
#endif

и тогда ваш проект Visual C ++ приведет к определению BUILDMYPROJECT при сборке myproject.dll

4 голосов
/ 16 сентября 2010

В двух словах:

(1) Создайте новый проект библиотеки C ++ / CLI.

(2) Напишите свой код.Для классов, которые должны быть доступны из вашего проекта C #, обязательно создайте их как классы CLR:

public ref class R {/*...*/};       // CLR class
public value class V {/*...*/};     // CLR struct
public interface class I {/*...*/}; // CLR interface

(3) Скомпилируйте проект и добавьте ссылку на него в ваш проект C #.

1 голос
/ 16 сентября 2010

Ниже приведен пример приложения, где я должен был сделать именно это.В моем случае мне нужна была DLL для переноса вызовов функций, которые были доступны только в .lib.Ключевой частью является extern "C" __declspec (dllexport) в декларации.Это в основном все, что вам нужно.Остальные просто использовали dllimport в приложении на C # и правильно распределяли.

1 голос
/ 16 сентября 2010
...