Предупреждение со сборкой 64bit dll - PullRequest
9 голосов
/ 26 августа 2010

заголовок экспорта 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

Хорошо работает. Но мне это не знакомо.
Дайте мне свое мнение.

Ответы [ 2 ]

11 голосов
/ 26 августа 2010

Обычно не рекомендуется указывать экспорт дважды для одной и той же функции. Если у вас уже есть __declspec(dllexport), вам не нужно указывать экспорт также в файле .def. И наоборот, если у вас есть экспорт, указанный в файле .def, тогда нет необходимости в __declspec(dllexport).

Я считаю, что причина предупреждения в том, что в сборках x86 __declspec(dllexport) экспортирует оформленное имя с начальным подчеркиванием, но 64-битный компилятор не украшает имена с начальным подчеркиванием, что приводит к дублированию. Чтобы убедиться в этом, вы можете взглянуть на 32-битную DLL в Dependency Walker и увидеть две экспортированные функции: "foo" и "_foo".

5 голосов
/ 26 августа 2010
Файлы

__declspec(dllexport) и .def - это два разных способа экспорта символов из DLL.Вам не нужны оба, и вы должны опустить одно из них.Метод __declspec гораздо более универсален для программ на c ++, так как он экспортирует имена с помощью манипуляции с ++, что позволяет экспортировать перегруженные функции, но, наоборот, затрудняет импорт имен через GetProcAddress.универсальный макрос типа EXPORT_DLL опасен, так как это означает, что вы не можете создать dll, которая использует другую dll, без одной dll, пытающейся экспортировать все символы обеих dll.

DevStudio автоматически создаетсимвол в проектах dll: <PROJECT>_EXPORTS, облегчающий и безопасный способ создания макроса 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 и Function2 соответственно.Функция 3 будет экспортирована через искаженное имя для компилятора, которое будет выглядеть примерно так: @Function3@@UAG_DB@Z.Это имя отличается для каждой перегрузки функции, что позволяет перегрузке работать.

Важно знать искажение имени __declspec, поскольку файлы .def не заботятся и просто экспортируют Function1, Function2 и Function3.

...