链接器未解析的外部符号 - 在 dll 中找不到函数
Linker unresolved external symbols - can't find functions in dll
我正在 Visual Studio C++ 中工作。
我做了一个class带非静态函数的,打包成一个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;
}
我可以确保 hGetProcIDDLL
和 func_create_class
已成功初始化(我已经用 if
测试了它们,但在这里我删除了 if
)。
当我运行这个项目时,我可以看到create_class
显示在控制台上,因为那个函数中有std::cout << __FUNCTION__ << std::endl;
。所以一切看起来都很好。
但是,当我使用未注释的代码 pf->func(1, "toto")
进行编译时,出现链接器 (LNK2019) 错误:
Error 1 error LNK2019: unresolved external symbol
"__declspec(dllimport) public: void __thiscall
Functions::func(int,class std::basic_string,class std::allocator >)"
(__imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
referenced in function _main c:\documents\visual studio
2013\Projects\testLoadDmcDLL\testLoadDmcDLL\main.obj testLoadDmcDLL
class 定义与导出不太正确,它应该是这样的形式;
class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
void func(int, std::string); // MATHFUNCSDLL_API removed
};
导出 class 后,将导出其所有成员。
你没有提到 MATHFUNCSDLL_EXPORTS
在编译过程中是如何定义的(从命令行或者可能在 stdafx.h 中),但是确保它是在构建 dll 时定义的,而不是在构建exe。一定要 link 反对用 .dll 生成的 .lib。
关于 LoadLibrary
和 GetProcAddress
用法的注释;如果需要动态加载dll,则需要获取绑定到导出函数的C++ class 成员函数。我还没有看到这个的成功实施,或者它是否合理。如果需要使用 LoadLibrary
和 GetProcAddress
,请考虑使用抽象 class 并在某种工厂中创建对象。
你没有详细说明动态加载dll的动机,但也可以考虑延迟加载dll。
如果动机是延迟加载 dll,但始终使用同一个 dll,那么延迟加载 linking 可能会有所帮助。如果动机是基于某些运行时参数(或配置)加载未知的 dll(通过 name/location),那么虚拟基础 class 和作为对象工厂的单个 C 风格函数是可能是首选解决方案。
有一个good code project article on this describing various solutions for this. In particular using the abstract base class非常便携
如果您不依赖导入库而是调用 GetProcAddress
,则您需要为要导入的每个函数执行此操作。您从未为 __imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z
调用 GetProcAddress
(这就是您的 Functions::func
在 DLL 中被破坏的方式)。
此外,请注意您从 GetProcAddress
获得了一个函数指针。虽然它指向实现 pf->func
的代码,但不使用成员函数调用语法调用函数指针。
根本问题是 GetProcAddress
确实是为 C 而不是 C++ 设计的。
我正在 Visual Studio C++ 中工作。
我做了一个class带非静态函数的,打包成一个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;
}
我可以确保 hGetProcIDDLL
和 func_create_class
已成功初始化(我已经用 if
测试了它们,但在这里我删除了 if
)。
当我运行这个项目时,我可以看到create_class
显示在控制台上,因为那个函数中有std::cout << __FUNCTION__ << std::endl;
。所以一切看起来都很好。
但是,当我使用未注释的代码 pf->func(1, "toto")
进行编译时,出现链接器 (LNK2019) 错误:
Error 1 error LNK2019: unresolved external symbol "__declspec(dllimport) public: void __thiscall Functions::func(int,class std::basic_string,class std::allocator >)" (__imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function _main c:\documents\visual studio 2013\Projects\testLoadDmcDLL\testLoadDmcDLL\main.obj testLoadDmcDLL
class 定义与导出不太正确,它应该是这样的形式;
class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
void func(int, std::string); // MATHFUNCSDLL_API removed
};
导出 class 后,将导出其所有成员。
你没有提到 MATHFUNCSDLL_EXPORTS
在编译过程中是如何定义的(从命令行或者可能在 stdafx.h 中),但是确保它是在构建 dll 时定义的,而不是在构建exe。一定要 link 反对用 .dll 生成的 .lib。
关于 LoadLibrary
和 GetProcAddress
用法的注释;如果需要动态加载dll,则需要获取绑定到导出函数的C++ class 成员函数。我还没有看到这个的成功实施,或者它是否合理。如果需要使用 LoadLibrary
和 GetProcAddress
,请考虑使用抽象 class 并在某种工厂中创建对象。
你没有详细说明动态加载dll的动机,但也可以考虑延迟加载dll。
如果动机是延迟加载 dll,但始终使用同一个 dll,那么延迟加载 linking 可能会有所帮助。如果动机是基于某些运行时参数(或配置)加载未知的 dll(通过 name/location),那么虚拟基础 class 和作为对象工厂的单个 C 风格函数是可能是首选解决方案。
有一个good code project article on this describing various solutions for this. In particular using the abstract base class非常便携
如果您不依赖导入库而是调用 GetProcAddress
,则您需要为要导入的每个函数执行此操作。您从未为 __imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z
调用 GetProcAddress
(这就是您的 Functions::func
在 DLL 中被破坏的方式)。
此外,请注意您从 GetProcAddress
获得了一个函数指针。虽然它指向实现 pf->func
的代码,但不使用成员函数调用语法调用函数指针。
根本问题是 GetProcAddress
确实是为 C 而不是 C++ 设计的。