C++ 在DLL客户端中使用dllimport时出错
我目前正在创建一个DLL和客户端,它使用internet上很多地方提到的存储过程。基本上,创建一个DLL项目,它实际上在project.h文件中定义了一个项目 大概是这样的:C++ 在DLL客户端中使用dllimport时出错,c++,visual-studio,visual-c++,dll,C++,Visual Studio,Visual C++,Dll,我目前正在创建一个DLL和客户端,它使用internet上很多地方提到的存储过程。基本上,创建一个DLL项目,它实际上在project.h文件中定义了一个项目 大概是这样的: // Assume the name of the project is SanProj and the header file is SanProj.h #ifdef SANPROJ_EXPORTS #define SANPROJ_API __declspec(dllexport) #else #defi
// 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中使用SANPROJ_导出进行“导出”声明,在用作客户端时使用“导入”声明。例如,假设我们有一个带有货币类的头文件:
// 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);
}
上述类构成DLL项目的契约。现在让我们看一下客户端项目文件,它是一个带有main
函数的单一类:
#include "currency.hpp"
#include "allccy.hpp"
#include <iostream>
using namespace SanProj;
int main(int argc, char* argv[])
{
USDCurrency uccy;
std::cout << uccy;
}
毫不奇怪,当我从SanProj.h
文件中删除dllimport
部分并创建可执行文件时,这个错误就消失了
我的问题是,如果我们不能根据头编译客户机,IDE生成的dllimport
有什么意义?是否有方法可以继续将头与dllimport
和dllexports
一起使用,并删除链接器错误?另外,为什么它试图从LIB文件解析具有dllimport
的符号
TIA,/佐助 编辑:VisualStudio使用的链接器命令;如您所见,它有LIB文件 /输出:“E:\vsprojects\SomeSln\Release\testdll.exe”/INCREMENTAL:NO /NOLOGO“E:\vsprojects\SomeSln\Release\SanProj.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”/MANIFEST /清单文件:“Release\testdll.exe.intermediate.manifest” /ALLOWISOLATION/MANIFESTUAC:“level='asInvoker'uiAccess='false'” /调试/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:QUEUE
它特别抱怨
USDCurrency
类的构造函数和析构函数,但是您的代码没有显示这些方法被SANPROJ_API
修饰
由于您在标题中定义了
USDCurrency
构造函数,当您从类USDCurrency
中删除dllimport
时,您得到的是一个在当前项目中定义的实现,而不是对DLL中定义的实现的引用。其他人都克服了这一点,我也会
当编译器添加libs时,编译器只执行以下操作:编译。链接器链接(doh)。您的问题似乎是一个链接器配置问题,有很多方法可以解决这个问题
如果多项目解决方案文件(.sln)同时包含DLL项目和EXE项目,则可以通过将DLL项目设置为EXE项目中的EXE项目“引用”来建立显式依赖关系。在此范围内,确保“链接库依赖项”标记为“true”
从VS2005开始,引用配置实际上是一个.NET添加,尽管它仍然适用于标准C/C++项目。您可以跳过该选项,并将导入库配置为在EXE项目的链接器/输入设置上隐式链接。名为“链接库依赖项”的设置也可以标记为true。这还需要配置解决方案项目依赖项(生成/项目依赖项…)。在本例中,您选择EXE项目作为“依赖于…”,并检查DLL项目。这可确保每当重建DLL项目并创建新的导入库时,都会重新链接EXE
如果需要,可以提供所有这些的屏幕截图。经过几次尝试之后,建立它已成为一种旧习惯。在这一点上,我相当肯定我可以盲着做。编辑:肯定我错了,因为jcopenha的答案就是答案。链接器抱怨没有在DLL中导出的构造函数和析构函数。然而,其余的仍然有效 [……] 您应该有两个构建目标(或项目,取决于您使用的环境) 第一个目标将构建DLL。此目标需要生成的文件基于您报告的内容:
currency.hpp
allccy.hpp
可能还有基类“currency”的实现。为了使用currency.hpp文件作为DLL导出函数的定义,必须在预处理器定义中定义SANPROJ_导出。
此目标将生成一个.DLL文件,并且可能(取决于配置)生成一个.lib文件。它还可能生成其他文件,如库导出的文本表示形式(一个.DEF文件)
然后,您需要构建应用程序(第二个目标/项目):
您需要的头文件与#include部分的库完全相同。请确保不要定义SANPROJ_导出,否则编译器将再次尝试导出Simbol,而不是导入它们。
然后,您需要向编译器和链接器添加以下设置:
- 将包含.hpp头的目录添加到include路径
- 将目录添加到链接器(lib)的库路径中 包含.lib文件
- 告诉链接器也链接到您刚刚创建的.lib(添加lib文件的全名,假设DLL名为“currency”,那么它可能是“currency.lib”)
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)
currency.hpp
allccy.hpp