1

好的,我开始明白为什么它被称为 Dll Hell。
这是我得到的代码

// API.h file
#ifdef EXPORTS
    #define API __declspec(dllexport)
#else
    #define API __declspec(dllimport)
#endif

struct API IClass {
   virtual void foo() = 0;
}

extern "C" API IClass* CreateClass(const char* type);

// Impl1.h
class Impl1: public IClass
{
   //...
}

// API.cpp file
#include "Impl1.h"
#include "Impl2.h"
#include "ImplX.h"

extern "C" API IClass* CreateClass(const char* type)
{
    if (type == "type1")
        return new Impl1();

    // ...
    return 0;
}

我收到链接器警告

warning LNK4217: locally defined symbol ??0IClass@DG@@QAE@XZ (public: __thiscall IClass::IClass(void)) imported in function... 

我知道发生这种情况是因为我已经在所有 Impl 中导入了这些符号,但另一方面,它们现在是本地的,因为我正在作为 API 一部分的工厂中编译它们。

1)我应该忽略警告还是有不同的方法来解决这个问题?
2)我应该保留默认的 __thiscall 还是更改为 __stdcall ?

编辑
不导出IClass帮助我删除了警告。
另一个问题出现了,我不确定同样的方法可以解决这个问题。
让我们假设IClass也有一个方法virtual bar(IData* data) = 0
如果我希望客户能够创建实例,IData我需要将其导出到 dll 中,回到 impl 中的原始问题。除非我也为它们创建创建函数,但这对于简单的数据结构来说似乎有点太多开销。

所以基本上问题是,如何在IData不将它们导出到 DLL 的情况下向客户端公开?

4

1 回答 1

2

如果您喜欢 COM 之类的东西:无需通过以下方式导出接口

__declspec(dllexport|import).

调用约定是一个相当古老的概念,并且与 x64 有任何相关性(Windows 和 UNIX 只有一个 64 位调用约定!)您在 32 位上的选择将介于__cdecl__stdcall. 第一条规则应该是:保持一致!这两种约定本身都很好。(除非你打算使用va_args(你不应该使用,因为它们是纯粹的邪恶)......)

__stdcall由 COM 和 WinAPI 使用,而标准库大多使用__cdecl. 就性能而言,它完全无关紧要(stackoverflow 上有一篇关于调用约定的速度差异的帖子)。

警告可能是由于您正在导出类而不是构造函数,因此我建议不要导出类...

于 2012-07-25T11:09:54.170 回答