1. dll的创建
1.1 使用 __declspec(dllexport) 创建dll
首先在VS中的Visual C++中创建一个Win32 Project,取名为Dll1。在Application Type中选择DLL,在Additional options中选择Empty project,即创建一个空的动态链接库工程。
然后为工程添加一个C++源文件:Dll1.cpp,假设我要实现的是加法和减法运算,则代码如下
extern "C" __declspec(dllexport) int add(int a, int b){
return a + b;
}
extern "C" __declspec(dllexport) int subtract(int a, int b){
return a - b;
}
1.2 使用模块定义(.def)文件创建dll
使用def文件创建dll的话就不再需要__declspec(dllexport),因此将代码写成最原始的样子:
int add(int a, int b){
return a + b;
}
int subtract(int a, int b){
return a - b;
}
同时为工程创建一个后缀名为.def的文件,并添加进工程,编辑其内容为:
LIBRARY Dll1
EXPORTS
add
subtract
其中LIBRARY语句用于指定动态链接库的名称,该名称与生成的动态链接库名称一定要匹配。EXPORTS语句用于表明dll将要导出的函数,以及为这些导出函数指定的符号名。
将该模块定义文件链接到工程中,方法为工程属性页面>链接器>输入>模块定义文件中写入“Dll1.def”。
2. dll的使用
2.1 隐式链接方式加载dll
将生成好的Dll1.dll和Dll1.lib复制到对话框程序所在的文件夹,然后在CXXXDlg.h中注册动态链接库的引入库文件。因为.lib文件包含了Dll1.dll中导出函数的符号名,相当于告诉对话框程序相关函数应该去dll中调用。然后在CXXXDlg.cpp中声明外部函数:
#pragma comment(lib,"Dll1.lib")
然后在CXXXDlg.cpp中声明外部函数:
_declspec(dllimport) int add(int a, int b);
_declspec(dllimport) int subtract(int a, int b);
//另一种常用方法
//===============================================================
//要导出静态库时,导出库的工程要加预编译宏STATIC_LIBRARY,使用库的工程什么也要加STATIC_LIBRARY宏
//要导出动态库时,导出库的工程要加预编译宏EXPORT,使用库的工程什么也不用加
//===============================================================
#ifdef EXPORT //导出库
#define _API_ __declspec(dllexport)
#else //导入库
#define _API_ __declspec(dllimport)
#endif //EXPORT
#ifdef STATIC_LIBRARY //导出静态库
#define EBAPI int
#else //导出动态库
#define EBAPI extern "C" _API_ int
#endif //STATIC_LIBRARY
这样我们就可以使用这两个函数了。为两个按钮添加事件响应程序,并添加如下代码:
void CXXXDlg::OnBtnAdd()
{
// TODO: Add your control notification handler code here
CString str;
str.Format(_T("5 + 3 = %d"), add(5, 3));
MessageBox(str);
}
2.2 显示加载方式加载dll
另一种是通过LoadLiabrary函数显示加载dll。代码如下。需要注意的是这时候我们不再需要注册.lib文件,也不需要声明外部函数。只要在需要使用的地方调用dll文件即可。
void CXXXDlg::OnBtnSubtract()
{
// TODO: Add your control notification handler code here
HINSTANCE hInst;
hInst = LoadLibrary(L"Dll1.dll");
typedef int(*SUBPROC)(int a, int b);
SUBPROC Sub = (SUBPROC)GetProcAddress(hInst, "subtract");
CString str;
str.Format(_T("5-3=%d"), Sub(5, 3));
FreeLibrary(hInst); //LoadLibrary后要记得FreeLibrary
MessageBox(str);
}
2.3 两种加载方式对比
通过以上的例子,可以看到隐式链接和动态加载两种加载dll的方式各有优点。
隐式链接方式实现简单,一开始就把dll加载进来,在需要调用的时候直接调用即可。但是如果程序要访问十多个dll,如果都采用隐式链接方式加载他们的话,在该程序启动时,这些dll都需要被加载到内存中,并映射到调用进程的地址空间,这样将加大程序的启动时间。而且一般来说,在程序运行过程中只是在某个条件满足的情况下才需要访问某个dll中的函数,如在上述例子中,我只有在点击按钮时才需要访问dll,其他情况下并不需要访问。这样如果所有dll都被加载到内存中,资源浪费是比较严重的。
显示加载的方法则可以解决上述问题,dll只有在需要用到的时候才会被加载到内存中。另外,其实采用隐式链接方式访问dll时,在程序启动时也是通过调用LoadLibrary函数加载该进程需要的动态链接库的。
原文:https://blog.csdn.net/elaine_bao/article/details/51784864