导出另一个dll的静态成员

时间:2013-08-15 22:36:25

标签: c++ templates dll dllexport

我有一个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

我也试过that

之类的东西
template <class T>
int base<T>::buf;

int base<int>::buf;

但得到了同样的错误。

一切都在没有我的静态buf。

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

我正在使用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 明确加载。

我的第一次尝试是没有任何类或模板,只有全局功能,它工作。之后,我创建了一个模板类,将函数放入。原因是,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“我的包含路径”/ Zi / Gm- / Od /Fd"Debug\vc110.pdb“/ fp:precise / D” WIN32“/ D”_WINDOWS“/ D”_WIN32_WINDOWS = 0x0501“/ D”_DEBUG“/ 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 /PDD:"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

1 个答案:

答案 0 :(得分:0)

我发现此帖可能会回答您的问题https://anteru.net/blog/2008/11/19/318/

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