链接器未解析的外部符号 - 无法在dll

时间:2015-11-06 10:23:55

标签: c++ dll linker-errors lnk2019

我在使用Visual Studio C ++。

我创建了一个具有非静态函数的类,并将其打包为dll。这是生成我的dll的代码:

// head file
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_

#include <string>
#include <memory>

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

MATHFUNCSDLL_API class Functions
{
public:
    MATHFUNCSDLL_API void func(int, std::string);
};


extern "C" MATHFUNCSDLL_API Functions * __cdecl create_class();

#endif


// cpp file
#include "stdafx.h"
#include "Functions.h"
#include <iostream>

void Functions::func(int id, std::string name)
{
    std::cout << "Your ID: " << id << ". Your name: " << name << std::endl;
}

Functions * create_class()
{
    std::cout << __FUNCTION__ << std::endl;
    return new Functions();
}

现在我有一个动态加载这个dll的C ++项目。这是代码:

#include <iostream>
#include <Windows.h>
#include "../../testDmcDLL/testDmcDLL/Functions.h"
typedef Functions *(__stdcall *f_funci)();
int main(int argc, char ** argv)
{
    HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents\\Visual Studio 2013\\Projects\\testDmcDLL\\Debug\\testDmcDLL.dll");
    f_funci func_create_class = (f_funci)GetProcAddress(hGetProcIDDLL, "create_class");
    Functions * pf = func_create_class();
    ////LNK error////pf->func(1, "toto");
    system("pause");
    return 0;
}

我可以确保hGetProcIDDLLfunc_create_class已成功初始化(我已使用if对其进行了测试,但此处我删除了if)。

当我运行这个项目时,我可以看到控制台上显示create_class,因为该函数中有std::cout << __FUNCTION__ << std::endl;。所以一切都很好。

但是,当我使用未注释的代码pf->func(1, "toto")编译它时,我得到一个链接器(LNK2019)错误:

  

错误1错误LNK2019:未解析的外部符号   “__declspec(dllimport)public:void __thiscall   函数:: func(int,class std :: basic_string,class std :: allocator&gt;)“   (__imp_ FUNC?@ @@功能QAEXHV?$ basic_string的@ DU?$ char_traits @ d @ @@ STD V'$分配器@ d @ @@ 2 STD @@@ Z)   在函数_main c:\ documents \ visual studio中引用   2013 \ Projects \ testLoadDmcDLL \ testLoadDmcDLL \ main.obj testLoadDmcDLL

2 个答案:

答案 0 :(得分:1)

对于导出,类定义不太正确,它应该是以下形式;

class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
    void func(int, std::string); // MATHFUNCSDLL_API removed
};

导出类后,将导出其所有成员。

您没有提到在编译期间(从命令行或可能在stdafx.h中)定义MATHFUNCSDLL_EXPORTS的方式,但确保在构建dll时定义它,但在构建时不能定义可执行程序。请务必链接使用.dll生成的.lib。

有关LoadLibraryGetProcAddress用法的说明;如果需要动态加载dll,则需要将C ++类成员函数绑定到导出的函数。我没有看到成功实施这一点,或者甚至是否合理。如果需要使用LoadLibraryGetProcAddress,请考虑使用抽象类并在某种工厂中创建对象。

您没有详细说明动态加载dll的动机,但也可以考虑加载dll的延迟。

如果动机是延迟加载dll,但总是使用相同的dll,那么延迟加载链接可能会有所帮助。如果动机是基于某些运行时参数(或配置)加载未知的dll(按名称/位置),那么虚拟基类和作为对象工厂的单个C风格函数可能是首选解决方案。 / p>

有一篇good code project文章描述了各种解决方案。特别是使用abstract base class非常便携。

答案 1 :(得分:0)

如果您不依赖导入库但请致电GetProcAddress,则需要为您要导入的每个功能执行此操作。您从未为GetProcAddress调用__imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z(这是Functions::func在DLL中被破坏的方式。)

另外,请注意,您从GetProcAddress获得了一个函数指针。虽然这指向实现pf->func的代码,但是不使用成员函数调用语法调用函数指针。

根本问题是GetProcAddress真的是为C而不是C ++设计的。