代码之家  ›  专栏  ›  技术社区  ›  Benjamin

生成64位dll时出现警告

  •  9
  • Benjamin  · 技术社区  · 14 年前

    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
    

    它运作良好。但我不熟悉。
    把你的意见告诉我。

    2 回复  |  直到 14 年前
        1
  •  11
  •   Dean Harding    14 年前

    通常,为同一个函数指定两次导出是不好的做法。如果你已经有了 __declspec(dllexport) 然后,您也不需要在.def文件中指定导出。相反,如果在.def文件中列出了导出,则不需要 _ declspec(dllexport) .

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

        2
  •  5
  •   Chris Becke    14 年前

    __declspec(dllexport) 和.def文件是两个 不同的 从DLL导出符号的方法。你不需要二者,应该省略其中之一。这个 __declspec 方法对于C++程序来说是更通用的,因为它用C++的方式来输出名字,允许重载函数被导出,但是相反地,这会使名称难以通过GETPosiNess导入。

    此外,使用类似宏的 EXPORT_DLL 这是危险的,因为这意味着如果没有一个dll尝试导出两个dll的所有符号,就无法构建使用另一个dll的dll。

    devstudio自动在dll项目上创建符号: <PROJECT>_EXPORTS 使创建导出宏变得容易和安全:

    #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 . 这个名称对于函数的每个重载都是不同的,这就是它允许重载工作的方式。

    重要的是要知道它的名字 第二章 as.def文件不关心,只导出 Function1 , 功能2 Function3 .