2

我有一个导出一些函数的 dll,以便第二个 dll 可以使用它们。两个 dll 都由 main 加载。现在我在导出 dll 中的数据成员时遇到了问题。

我有一个看起来像这样的模板类(temp.hpp):

template<typename T>
class __declspec(dllexport) base {
public:
    static T buf;
    static void do_smt(T val);
};

template<typename T>
void base<T>::do_smt(T val) {
    base<T>::buf = val;
}

从模板类 ( dll.h ) 继承的第二个类。此标头在 2 个 dll 之间共享。

#include "temp.hpp"

class __declspec(dllexport) child
    : public base <int> {};

dll.cpp看起来像:

#include "dll.h"

base<int> inter;
int base<int>::buf;

还有一些其他功能,所以我试图将其简化为基础。

这将编译并创建一个 .lib 和一个 .dll。现在我有另一个用.lib 编译的项目。主要是加载两个 dll,所以第二个 dll 可以使用do_smt(如果我删除static int buf. 但我收到一个错误,我的 buf 未解决。

Error   1   error LNK2001: unresolved external symbol "public: static int base<struct int>::buf" (?buf@?$base@Uint@@@@2HA)  module.obj

我也尝试过类似的东西

template <class T>
int base<T>::buf;

int base<int>::buf;

但得到了同样的错误。

没有我的静态缓冲区,一切正常。

如何使我的 buf 静态 buf 导出到我的 dll.cpp (dll.dll) 中,以便我的其他 dll 可以通过静态 do_smt 方法使用它?

我正在使用vs2012。

编辑:

dumpbin /exports dll.dll 返回:

File Type: DLL

  Section contains the following exports for dll.dll

    00000000 characteristics
    520D5353 time date stamp Fri Aug 16 00:16:51 2013
        0.00 version
           1 ordinal base
           5 number of functions
           5 number of names

    ordinal hint RVA      name

          1    0 000613E9 ??4?$base@Uint@@@@QAEAAV0@ABV0@@Z = @ILT+17380(??4?$base@Uint@@@@QAEAAV0@ABV0@@Z)
          2    1 0005F2BF ??4child@@QAEAAV0@ABV0@@Z = @ILT+8890(??4child@@QAEAAV0@ABV0@@Z)
          3    2 0014F594 ?buf@?$base@Uint@@@@2HA = ?buf@?$base@Uint@@@@2HA (public: static int base<int>::buf)
          4    3 0005D90B ?getdllDLLInit@@YAJPAUPlugInHeader@@@Z = @ILT+2310(?getdllDLLInit@@YAJPAUPlugInHeader@@@Z)
          5    4 0005F0BC dllDLL = @ILT+8375(_dllDLL)

  Summary

        4000 .data
        4000 .idata
       29000 .rdata
        9000 .reloc
        1000 .rsrc
       C6000 .text
       5C000 .textbss
        1000 .tls

似乎 buf 在 dll 中。

编辑2:

主要不是我写的,我没有代码。另外主要是没有真正加载dll.dll。它正在使用LoadLibrary加载库以检查一些信息(通过 getdllDLLInit (可能命名错误))并再次卸载它。dll.dll 位于 exe 的根目录中。如有必要,它将由 Windows 自动加载。其他 dll 由 .exe 使用LoadLibrary显式加载。

我的第一次尝试是没有任何类或模板,只有 gobal 函数并且它有效。之后,我创建了一个模板类,将函数放入其中。原因是,dll.dll 将与其他类型一起重用,所以我不必重写太多(只需更改继承class __declspec(dllexport) child: public base <some_other_type> {};并重新定义静态.. .) 我可以一次又一次地重写所有内容,但这将违反DRY原则。

编辑3:

在 willj 建议我在没有模板的情况下尝试它之后,我发现了一些新东西。问题是该方法位于标头内部而不是 cpp 内部。如果我只是重写模板

template<typename T>
class __declspec(dllexport) base {...};

class __declspec(dllexport) baseInt {...};

它仍然不起作用,但是如果我将方法与标题分开并将它们移动到 cpp 中(在我的情况下,移动base::buf到 cpp 更重要)它可以工作。我认为问题是,即使 base::buf 成员被正确编译为 dll.dll,其他项目在编译时也找不到定义,即使它是在 lib 中定义的。我不知道这是 msvc 中的错误还是正确的行为。我虽然通过从具有特定类型的基础继承来做到这一点。

由于我想使用模板和只有 1 个(全局)标题,我开始认为这个问题可能无法解决。

编辑4:

命令:

  • 编译

/FR"Debug\" /GS /analyze- /W3 /Zc:wchar_t /I"my include path's" /Zi /Gm- /Od /Fd"Debug\vc110.pdb" /fp:precise /D "WIN32" / D "_WINDOWS" /D "_WIN32_WINDOWS=0x0501" /D "_D​​EBUG" /D "_USRDLL" /D "NOMINMAX" /D "_CRT_SECURE_NO_WARNINGS" /D "_WINDLL" /errorReport:prompt /WX- /Zc:forScope /RTC1 / Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\test.pch"

  • 关联

/OUT:"Debug\test.dll" /MANIFEST /PDB:"Debug\test.pdb" /DYNAMICBASE:NO "dll.lib" "Winmm.lib" "kernel32.lib" "user32.lib" "gdi32.lib ““winspool.lib”“comdlg32.lib”“advapi32.lib”“shell32.lib”“ole32.lib”“oleaut32.lib”“uuid.lib”“odbc32.lib”“odbccp32.lib”/IMPLIB:“ Debug\test.lib" /DEBUG /DLL /MACHINE:X86 /SAFESEH /INCREMENTAL /PGD:"Debug\test.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile: "Debug\test.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /LIBPATH:"D:/prg/svn/branches/DLL/Debug" /LIBPATH:"D:\prg\svn\trunk\LIBS\boost \1.53.0\lib\msvc-32bit" /TLBID:1

4

1 回答 1

0

我发现这篇文章可能会回答您的问题https://anteru.net/blog/2008/11/19/318/

另外我认为这个问题是因为你没有在它自己的 dll 中实例化你的模板。一种解决方案是在与基类相同的 dll 中定义类。如果这会破坏类和模块的设计,您可以提取一个可以由child派生的类A,并将A放在与类相同的 dll 中。

于 2018-05-09T16:26:07.063 回答