Существуют три правильных способа сделать это:
- Используйте 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