Если вам нужен простой экспорт на C, используйте проект C, а не C ++. Библиотеки DLL C ++ полагаются на изменение имен для всех измов C ++ (пространства имен и т. Д.). Вы можете скомпилировать свой код как C, зайдя в настройки вашего проекта в C / C ++ -> Advanced, там есть опция «Compile As», которая соответствует переключателям компилятора / TP и / TC.
Если вы по-прежнему хотите использовать C ++ для написания внутренней части вашей библиотеки, но экспортировать некоторые функции без привязки для использования вне C ++, см. Второй раздел ниже.
Экспорт / импорт библиотек DLL в VC ++
На самом деле вам нужно определить условный макрос в заголовке, который будет включен во все исходные файлы в вашем проекте DLL:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Затем для функции, которую вы хотите экспортировать, вы используете LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
В проекте сборки библиотеки создайте определение, LIBRARY_EXPORTS
это приведет к тому, что ваши функции будут экспортированы для сборки DLL.
Поскольку LIBRARY_EXPORTS
не будет определен в проекте, использующем DLL, когда этот проект включает файл заголовка вашей библиотеки, вместо этого будут импортированы все функции.
Если ваша библиотека должна быть кросс-платформенной, вы можете определить LIBRARY_API как ничто, если не в Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
При использовании dllexport / dllimport вам не нужно использовать файлы DEF, если вы используете файлы DEF, вам не нужно использовать dllexport / dllimport. Эти два метода решают одну и ту же задачу разными способами, я считаю, что dllexport / dllimport - это рекомендуемый метод из двух.
Экспорт несвязанных функций из библиотеки DLL C ++ для LoadLibrary / PInvoke
Если вам нужно использовать LoadLibrary и GetProcAddress или, возможно, импортировать с другого языка (например, PInvoke из .NET или FFI в Python / R и т. Д.), Вы можете использовать extern "C"
встроенный с вашим dllexport, чтобы сообщить компилятору C ++ не искажать имена. И поскольку мы используем GetProcAddress вместо dllimport, нам не нужно выполнять танец ifdef сверху, просто простой dllexport:
Код:
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT int getEngineVersion() {
return 1;
}
EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
K.getGraphicsServer().addGraphicsDriver(
auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
);
}
А вот как выглядит экспорт с помощью Dumpbin / exports:
Dump of file opengl_plugin.dll
File Type: DLL
Section contains the following exports for opengl_plugin.dll
00000000 characteristics
49866068 time date stamp Sun Feb 01 19:54:32 2009
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
2 1 00011028 registerPlugin = @ILT+35(_registerPlugin)
Итак, этот код отлично работает:
m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");
m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
::GetProcAddress(m_hDLL, "registerPlugin")
);
extern C
удалит украшение, которое описывает типы параметров функции, но не украшение, которое описывает соглашение о вызове функции; б) чтобы удалить все декорации, вам необходимо указать (недекорированное) имя в файле DEF.