9

dll导出头

extern "C"
void _declspec(dllexport) __stdcall foo();

.def 文件

EXPORTS
foo         @1

当我通过 64 位构建配置构建 dll 时,我遇到了这个警告。

警告 LNK4197:多次指定导出“foo”;使用第一个规范

但如果我通过 32 位构建配置构建 dll,则永远不会出现警告。
问题是什么?有什么区别。

在接口的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

它运作良好。但这对我来说并不熟悉。
给我你的任何意见。

4

2 回答 2

11

为同一个函数指定两次导出通常不是一个好习惯。如果您已经拥有,__declspec(dllexport)那么您也不需要在 .def 文件中指定导出。相反,如果您在 .def 文件中列出了导出,则不需要__declspec(dllexport).

我相信警告的原因是在 x86 构建中,__declspec(dllexport)导出带有前导下划线的修饰名称,但 64 位编译器不使用前导下划线修饰名称,从而导致重复。为了验证这一点,您可以查看 Dependency Walker 中的 32 位 DLL,您应该会看到两个导出的函数,“foo”和“_foo”。

于 2010-08-26T05:54:43.230 回答
5

__declspec(dllexport)和 .def 文件是从 dll 中导出符号的两种不同方式。你不需要两者,应该省略其中一个。该__declspec方法对于 c++ 程序更加通用,因为它使用 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@0Function2获得。Function3 将通过编译器特定的重整名称导出,该名称类似于:@Function3@@UAG_DB@Z. 这个名称对于函数的每个重载都是不同的,这就是它允许重载工作的方式。

重要的是要知道__declspec.def 文件的名称修饰不关心,只会导出Function1,Function2Function3.

于 2010-08-26T06:05:48.623 回答