заголовок экспорта dll
extern "C"
void _declspec(dllexport) __stdcall foo();
.def file
EXPORTS
foo @1
Когда я собираю dll с помощью 64-битной конфигурации сборки, я встречаю это предупреждение.
предупреждение LNK4197: экспорт 'foo' указан несколько раз ; используя первую спецификацию
Но если я соберу dll с помощью 32-битной конфигурации, предупреждение никогда не появится.
В чем проблема? В чем разница.
В заголовке dll для интерфейса мы обычно используем эту технику,
#ifdef EXPORT_DLL
#define BASICAPI _declspec(dllexport)
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
Но если файл def также существует, мы всегда будем встречать предупреждение при создании 64-битной dll.
Так стоит ли нам писать такие коды?
#ifdef EXPORT_DLL
#define BASICAPI
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
Это работает хорошо. Но это мне не знакомо.
Дайте мне свое мнение.
Обычно указывать экспорт дважды для одной и той же функции не рекомендуется. Если у вас уже есть __declspec(dllexport)
, вам также не нужно указывать экспорт в файле .def.И наоборот, если экспорт указан в файле .def, то нет необходимости в __declspec(dllexport)
.
Я полагаю, что причина предупреждения заключается в том, что в сборках x86 __declspec(dllexport)
экспортирует оформленное имя с начальным символом подчеркивания, но 64-разрядный компилятор не украшает имена начальным символом. подчеркивание, ведущее к дубликату. Чтобы убедиться в этом, вы можете посмотреть на 32-битную DLL в Dependency Walker, и вы должны увидеть две экспортированные функции, «foo» и «_foo».
__declspec(dllexport)
и файлы .def — это два различных способа экспорта символов из dll. Вам не нужны оба, и вы должны опустить один из них. Метод __declspec
гораздо более универсален для программ на С++, поскольку он экспортирует имена с исправлением С++, позволяя экспортировать перегруженные функции, но, наоборот, затрудняет импорт имен через GetProcAddress.
Кроме того, использование универсального макроса, такого как EXPORT_DLL
, опасно, так как это означает, что вы не можете создать dll, использующую другую dll, без того, чтобы одна dll пыталась экспортировать все символы обеих dll. .
DevStudio автоматически создает символ для dll-проектов:
, что позволяет легко и безопасно создавать макрос EXPORT:
#ifdef EXPORT
#undef EXPORT
#endif
#ifdef PROJECTNAMEHERE_EXPORTS
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXTERN_C EXPORT void __stdcall Function1(void);
EXTERN_C EXPORT void __cdecl Function2(...);
EXPORT void Function3(void);
Функции 1 и 2 можно получить с помощью GetProcAddress как _Function1. @0
и Функция2
соответственно. Function3 будет экспортироваться с помощью измененного имени компилятора, которое будет выглядеть примерно так: @Function3@@UAG_DB@Z
. Это имя отличается для каждой перегрузки функции, что позволяет перегрузке работать.
Важно знать искажение имени __declspec
, так как файлы .def не имеют значения и будут просто экспортировать Функция1
, Функция2
и Функция3
.