dllexport与dllimport
dllexport与dllimport存储级属性是微软对C和C++的扩展,可用于从dll中导入或导出函数、数据、对象(objects)
语法
__declspec( dllimport ) declarator
__declspec( dllexport ) declarator
这些属性显式地定义了dll提供给客户端的接口,客户端可以是一个可执行文件或者另一个dll。dllexport声明的使用免去了模块定义(.def)文件的使用,def文件至少包含相关导出函数的声明。
dllexport暴露的是函数的修饰名(decorated name)1。如果想避免函数名修饰,使用C函数或者使用extern "C"
2修饰C++函数。
示例代码:
//DLL项目头文件
#pragma once
#include <string>
#ifdef DLLTEST_EXPORTS
# define DLL_API _declspec(dllexport)
# else
# define DLL_API _declspec(dllimport)
#endif // DLLTEST_EXPORTS
class DLL_API DLLClass
{
public:
int add(int a, int b);
std::string add(std::string, std::string);
static int static_var;
};
extern DLL_API int a;
extern "C" DLL_API int aa;
namespace DLLNamespace
{
extern DLL_API int b;
}
DLL_API int addFunc(int, int);
extern "C" DLL_API int addFunc2(int, int);
//DLL项目CPP
#include "DLLClass.h"
int DLLClass::add(int a, int b)
{
return a + b;
}
std::string DLLClass::add(std::string s1, std::string s2)
{
return s1 + s2;
}
int DLLClass::static_var = 3;
int a = 1;
int aa = 11;
namespace DLLNamespace
{
int b = 2;
}
int addFunc(int a, int b)
{
return a + b;
}
int addFunc2(int a, int b)
{
return a + b;
}
//测试代码
#include <iostream>
#include "DLLClass.h"
using namespace std;
int main()
{
DLLClass obj;
cout << obj.add(1, 1) << endl;
cout << obj.add("hello ", "world!") << endl;
cout << "a: " << a << endl;
cout << "b: " << DLLNamespace::b << endl;
cout << "static member: " << DLLClass::static_var << endl;
cout << addFunc(1, 1) << endl;
cout << addFunc2(1, 1) << endl;
}
以下是dumpbin查看dll导出的所有定义
ordinal hint RVA name
1 0 0001126C ??4DLLClass@@QAEAAV0@$$QAV0@@Z = @ILT+615(??4DLLClass@@QAEAAV0@$$QAV0@@Z)
2 1 00011050 ??4DLLClass@@QAEAAV0@ABV0@@Z = @ILT+75(??4DLLClass@@QAEAAV0@ABV0@@Z)
3 2 00020004 ?a@@3HA = ?a@@3HA (int a)
4 3 0001151E ?add@DLLClass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V23@0@Z = @ILT+1305(?add@DLLClass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V23@0@Z)
5 4 000112AD ?add@DLLClass@@QAEHHH@Z = @ILT+680(?add@DLLClass@@QAEHHH@Z)
6 5 0001103C ?addFunc@@YAHHH@Z = @ILT+55(?addFunc@@YAHHH@Z)
7 6 0002000C ?b@DLLNamespace@@3HA = ?b@DLLNamespace@@3HA (int DLLNamespace::b)
8 7 00020000 ?static_var@DLLClass@@2HA = ?static_var@DLLClass@@2HA (public: static int DLLClass::static_var)
9 8 00020008 aa = _aa
10 9 0001148D addFunc2 = @ILT+1160(_addFunc2)
我们可以看到,重载函数实现的原理就是使用函数名修饰(4和5),使用extern "C"修饰的函数或变量导出定义时的名字与原函数名或变量名相同(9和10)
参考:
- https://docs.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?redirectedfrom=MSDN&view=msvc-170