在DLL客户端中使用dllimport时出错
Error when using dllimport in a DLL client
我目前正在创建一个DLL和客户端,该客户端使用互联网上很多地方提到的存储过程。基本上,创建一个DLL项目,该项目在project.h文件中实际定义了project_EXPORTS。
类似这样的东西:
// Assume the name of the project is SanProj and the header file is SanProj.h
#ifdef SANPROJ_EXPORTS
#define SANPROJ_API __declspec(dllexport)
#else
#define SANPROJ_API __declspec(dllimport)
#endif
现在使用这个头的正常方式是将其包括在API类的所有头中;导出";当在DLL中时的声明;导入";用作客户端时的声明。例如,假设我们有一个带有货币类的头文件:
// currency.hpp
#include "SanProj.h"
#include <ostream>
#include <string>
namespace SanProj {
class SANPROJ_API Currency {
public:
Currency();
const std::string& name();
const std::string& code();
bool empty() const;
protected:
std::string name_;
std::string code_;
};
SANPROJ_API bool operator==(const Currency&,
const Currency&);
SANPROJ_API bool operator!=(const Currency&,
const Currency&);
SANPROJ_API std::ostream& operator<<(std::ostream& out, Currency& c);
}
以及另一个具有特定货币的头文件:
// allccy.hpp
namespace SanProj {
class SANPROJ_API USDCurrency : public Currency {
public:
USDCurrency() {
name_ = "American Dollar";
code_ = "USD";
}
};
class SANPROJ_API CADCurrency : public Currency {
public:
CADCurrency() {
name_ = "Canadian Dollar";
code_ = "CAD";
}
};
}
上述类构成DLL项目的合同。现在让我们来看一下客户端项目文件,它是一个具有main
函数的类:
#include "currency.hpp"
#include "allccy.hpp"
#include <iostream>
using namespace SanProj;
int main(int argc, char* argv[])
{
USDCurrency uccy;
std::cout << uccy;
}
假设所有的引用/设置都已经在VisualStudio项目中完成,我在尝试编译客户端时会出现以下错误:
1>testdll.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall SanProj::USDCurrency::~USDCurrency(void)" (__imp_??1USDCurrency@SanProj@@QAE@XZ)
1>testdll.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall SanProj::USDCurrency::USDCurrency(void)" (__imp_??0USDCurrency@SanProj@@QAE@XZ)
毫不奇怪,当我从SanProj.h
文件中删除dllimport
部分并创建可执行文件时,这个错误就会消失。
我的问题是,如果我们不能根据头编译客户端,那么IDE生成的dllimport
有什么意义?有没有一种方法可以继续将标头与dllimport
和dllexports
一起使用并删除链接器错误?此外,它为什么试图从LIB文件中解析具有dllimport
的符号?
TIA,
/佐助
EDIT:VisualStudio使用的链接器命令;正如您所看到的,它有LIB文件。
/OUT:";E: \vsprojects\SomeSln\Release \testdll.exe"增量:否/NOLOGO";E: \vsprojects\SomeSln\Release \SanProj.lib"quot;kernel32.lib";"user32.lib"gdi32.lib"winspool.lib"comdlg32.lib"advapi32.lib";"shell32.lib"ole32.lib"oleaut32.lib"uuid.lib"odbc32.lib";"odbccp32.lib"/舱单/ManifestFile:"Release \testdll.exe.intermediate.manifest"/允许隔离/歧管:";level='asInvoker'uiAccess='false'"/DEBUG/PDB:;E: \vsprojects\SomeSln\Release \testdll.pdb"/子系统:控制台/OPT:REF/OPT:ICF/PGD:";E: \vsprojects\SomeSln\Release \testdll.pgd"LTCG/TLBID:1/DYNAMICBASE/NXCOMPAT/MACHINE:X86/ERRORREPORT:队列
编辑:当然我错了,因为jcopenha的答案就是答案。链接器抱怨没有在DLL中导出的构造函数和析构函数丢失。然而,其余部分仍然有效。
[…]
您应该有两个构建目标(或项目,具体取决于您使用的环境)。
第一个目标将生成DLL。此目标需要构建的文件基于您报告的内容:
currency.hpp
allccy.hpp
可能还有基类"currency"的实现。您必须在预处理器定义中定义了SANPROJ_EXPORTS,才能将currency.hpp文件用作DLL导出的函数的定义。此目标将生成一个.DLL文件,并且可能(取决于配置)生成一个.lib文件。它还可以生成其他文件,如库导出的文本表示(.DEF文件)。
然后,您需要构建您的应用程序(第二个目标/项目):您需要的头文件与#include部分的库完全相同。只需确保不要定义SANPROJ_EXPORTS,否则编译器将尝试再次导出simbols,而不是导入它们。然后,您需要向编译器和链接器添加以下设置:
将包含.hpp标头的目录添加到包含路径中。
将目录添加到链接器(lib)的库路径包含.lib文件。
告诉链接器也链接到你刚刚创建的.lib(添加你的lib文件的全名,假设DLL名为"currency",它可能是"currency.lib"。
在何处以及如何添加此设置取决于所使用的工具链/环境和编译器。
最后,请确保编译后的可执行文件能够在项目文件夹或系统目录(在PATH中)中找到DLL,否则它将不会启动。如果可执行文件位于与用于生成DLL的文件夹不同的文件夹中,则只需使用生成后步骤复制DLL即可。
删除_dllimport部分将构建项目,这可能是因为编译器找到了头和要导出的函数的实现,并将所有函数静态构建到可执行文件中。
假设您不在.NET的"托管世界"中,并且我们谈论的是Windows,如果您想分发您的库,还有一些要点需要考虑,但这是另一个答案。
它特别抱怨USDCurrency
类的构造函数和析构函数,但您的代码没有显示这些方法是用SANPROJ_API
装饰的。
由于您在头中定义了USDCurrency
构造函数,所以当您从类USDCurrency
中删除dllimport
时,您得到的是在当前项目中定义的实现,而不是对DLL中定义的实施的引用。
其他人都打败了这一点,我也会。
对于添加库的编译器,编译器只会执行以下操作:编译。链接器链接(doh)。您的似乎是一个链接器配置问题,有很多方法可以解决这个问题。
如果您有一个同时包含DLL项目和EXE项目的多项目解决方案文件(.sln),则可以通过将DLL项目设置为EXE项目中的EXE项目"引用"来建立显式依赖关系。在此范围内,请确保"链接库依赖项"标记为"true"。
References配置实际上是从VS2005开始添加的.NET,尽管它仍然适用于标准C/C++项目。您可以跳过它,并将导入库配置为在EXE项目的Linker/Input设置上隐式链接。一个名为"链接库依赖项"的设置也可以在那里标记为true。这还需要您配置解决方案项目依赖项(生成/项目依赖项…)。在您的情况下,您将EXE项目选择为"依赖于..",并检查DLL项目。这样可以确保在重建DLL项目和创建新的导入库时重新链接EXE。
如果需要,所有这些的屏幕截图都是可用的。这已经成为一个老习惯,设置后几次周转。在这一点上,我相当肯定我可以做到盲目折叠。
这个问题似乎没有解决方案。我最终放弃了在客户端代码中使用dllimport
,性能受到了影响(
- 访问者访问变体并返回不同类型时出错
- 在Linux for Windows上编译C++代码时出错
- 读取文件的最后一行并输入到链接列表时出错
- 重载操作程序时出错>>用于类中的字符串 memebr
- 调用专用模板时出错"no matching function for call to [...]"
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- LINK 尝试使用 OpenSSL evp aes 256 c++ 时出错
- 在Google Kick start中提交时出错
- 在c++中访问int到类对象的映射时出错
- 分段错误当我试图运行程序时出错
- 使用dynamic_cast和构造函数时出错
- CHECK(调用)函数在Google Colab中出错
- 用pybind11包装C++抽象类时出错
- 为x86而非x64编译时出错
- 从R调用C++函数并对其进行集成时出错
- 这个函数哪里出错了
- C++ 创建包含链表和字符串的对象的链接列表时出错
- 为重写std::exception的库生成swig接口时出错
- 导入/导出变量时出错
- 在DLL客户端中使用dllimport时出错