在VS中创建和使用动态库

DLL(在基于UNIX的操作系统中也称为 共享库)是最有用的Windows组件之一。
• 可以用来共享代码和资源,并缩小应用程序的大小。
• DLL甚至可以使服务和扩展应用程序变得更加容易。

DLL使用C调用约定
• 只要平台,调用约定和链接约定匹配,就可以从用其它编程语言编写的应用程序中调用它。
• 客户端应用程序使用隐式链接,其中Windows在加载时将应用程序链接到DLL。通过此链接,应用程序可以调用DLL提供的函数,就像静态链接库中的一样。

创建一个DLL项目

1. 在Vs2017中创建DLL项目

1.1 在菜单栏中,选择 “文件” ->“新建”->“项目”,打开“ 新建项目”对话框。
1.2 选择 “Visual C++”->“Windows桌面”->“动态链接库”,设置文件名称及解决方案名称,选择确定按钮。
在这里插入图片描述
2. 向DLL项目添加头文件
2.1 在解决方案资源管理器中打开MathLibrary项目的快捷菜单,然后选择“ 添加” ->“ 新建项”。选择“ 头文件(.h)”。指定头文件的名称(例如MathLibrary.h),然后选择“ 添加”按钮。显示头文件。
2.2 添加头文件代码

#ifdef MATHLIBRARY_EXPORTS
// dllexport dllimport: https://docs.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?view=vs-2017
// __declspec(dllexport) 告诉编译器和链接器从DLL导出函数或变量,以供其它应用程序使用。
#define MATHLIBRARY_API __declspec(dllexport)
// 当未定义MATHLIBRARY_EXPORTS时,
// 例如,当客户端应用程序包含头文件时,MATHLIBRARY_API会将__declspec(dllimport)修饰符应用于声明。
#else
// __declspec(dllimport)该修饰符优化了应用程序中函数或变量的导入
#define MATHLIBRARY_API __declspec(dllimport)
#endif // MATHLIBRARY_EXPORTS
 
// The Fibonacci(斐波那契数列) recurrence relation describes a sequence F
// where F(n) is { n = 0, a
//               { n = 1, b
//               { n > 1, F(n-2) + F(n-1)
// for some initial integral values a and b.
// If the sequence is initialized F(0) = 1, F(1) = 1,
// then this relation produces the well-known Fibonacci
// sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
 
//初始化斐波那契关系序列
//这样F(0)= a,F(1)= b
//必须先调用此函数
extern "C" MATHLIBRARY_API void fibonacci_init(const unsigned long long a, const unsigned long long b);
 
//产生序列中的下一个值。
//成功返回true并更新当前值和索引;
//溢出时为false,保持当前值和索引不变。
extern "C" MATHLIBRARY_API bool fibonacci_next();
 
//获取序列中的当前值。
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
 
//获取当前值在序列中的位置。
extern "C" MATHLIBRARY_API unsigned fibonacci_index();

2.3 在解决方案资源管理器中打开MathLibrary项目的快捷菜单,然后选择“ 添加” ->“ 新建项”。选择“ C++文件(.cpp)”。指定源文件的名称(例如MathLibrary.h),然后选择“ 添加”按钮。显示源文件。
2.4 添加源文件代码

// MathLibrary.cpp : 定义 DLL 应用程序的导出函数。
//
 
#include "stdafx.h"
#include <utility>
#include <limits.h>
#include "MathLibrary.h"
 
//  DLL internal state variables:
static unsigned long long previous_;  // Previous value, if any
static unsigned long long current_;   // Current sequence value
static unsigned index_;
 
//初始化斐波那契关系序列
//这样F(0)= a,F(1)= b
//必须先调用此函数
void fibonacci_init(const unsigned long long a,
const unsigned long long b)
{
index_ = 0;
current_ = a;
previous_ = b;
}
 
//产生序列中的下一个值。
//成功返回true并更新当前值和索引;
//溢出时为false,保持当前值和索引不变。
bool fibonacci_next()
{
// 检查其值及其索引位置是否溢出
if ((ULLONG_MAX - previous_ < current_) ||
(ULLONG_MAX == index_))
{
return false;
}
 
// 特殊情况下,当index == 0时,仅返回b值
if (index_ > 0)
{
// 否则,计算下一个序列值
previous_ += current_;
}
 
std::swap(current_, previous_);
++index_;
return true;
}
 
//获取序列中的当前值。
unsigned long long fibonacci_current()
{
return current_;
}
 
//获取当前值在序列中的位置。
unsigned fibonacci_index()
{
return index_;
}

  1. 在菜单栏上,选择 “生成”->“生成解决方案”,编译器会创建一共可供其它程序使用的动态库。
    在这里插入图片描述

创建使用DLL的客户端应用

DLL使用条件:

  1. 需要找到声明DLL导出的标头
  2. 链接器的导入库
  3. DLL本身

如何实现:
一种解决方案是将所有这些文件复制到您的客户端项目中。
• 对于客户端开发过程中不太可能更改的第三方DLL,此方法可能是使用它们的最佳方法。
• 但是,当您还构建DLL时,最好避免重复。如果制作正在开发的DLL文件的本地副本,则可能会意外地在一个副本中更改头文件,而在另一个副本中更改头文件,或者使用过期的库。
为避免代码不同步,建议您在客户端项目中设置包含路径,以直接从DLL项目中包含DLL头文件。另外,在客户端项目中设置库路径以包括DLL项目中的DLL导入库。最后,将生成的DLL从DLL项目复制到客户端生成输出目录。此步骤允许您的客户应用程序端应用程序使用您生成的相同DLL代码。

属性页操作:

1.	包含头文件:属性页->C/C++ ->常规->附加包含目录下指定.h文件路径
包含头文件后,可编译,不能链接
2.	指定.lib库的依赖项:属性页->链接器->输入->附加依赖项,添加.lib
3.	告诉链接程序如何找到.lib:属性页->链接器->常规->附加库目录
绝对路径(.lib所在完整路径):如C:\Users\Administrator\source\repos\MathLibrarySolution\Debug
或填写相对路径(解决方案名称):..\..\MathLibrarySolution(解决方案名称)\$(IntDir)
此时,可以成功编译并链接,但可能存在找不到DLL问题。
4.	将DLL复制到生成输出目录的命令操作:属性页->生成事件->生成后事件->命令行,输入命令:
xcopy /y /d "..\..\MathLibrarySolution(解决方案名称)\$(IntDir)MathLibrary.dll(.dll文件名称)" "$(OutDir)"

1. 在VS2017中创建客户端应用程序

  1. 在VS2017中创建客户端应用程序
    1.1 新建项目
    在这里插入图片描述

2. 将DLL表头添加到包含路径

2.1 在菜单栏,选择“项目”,在MathClient的“ 属性页”对话框中,展开“ 配置属性”节点,再展开“ C / C ++”节点,然后选择“ 常规”。在“附加包含目录”,指定MathLibrary.h头文件的位置的路径,或浏览它【浏览到项目路径下即可】。
在这里插入图片描述
2.2 点击 “确定”按钮,则现在可以包含MathLibrary.h头文件,并使用它在客户端应用程序中声明的功能。

  1. MathClient.cpp代码:
// MathClient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include "pch.h"
#include <iostream>
// 属性页: 附加包含目录:选择含有MathLibrary.h的文件目录
#include "MathLibrary.h"
 
int main()
{
// 初始化斐波那契数列
fibonacci_init(1,3);
do
{
std::cout << fibonacci_index() << ": "
<< fibonacci_current() <<std::endl;
} while (fibonacci_next());
 
return 0;
}

  1. 此代码可以编译但不能链接。
    还需要做:
    (1)指定项目对MathLibrary.lib库的依赖项
    (2)告诉链接程序如何找到MathLibrary.lib文件

  2. 属性页 - >“链接器” -> “输入” ->“附加依赖项”,添加MathLibrary.lib
    在这里插入图片描述

  3. 属性页 - >“链接器” -> “常规” ->“附加库目录”,添加MathLibrary.lib所在目录
    在这里插入图片描述
    或相对路径…\MathLibrarySolution(解决方案名称)$(IntDir)
    在这里插入图片描述

  4. 此时运行,可以成功编译并链接,此时操作系统加载应用程序时,它将查找MathLibrary.dll,如果在某些系统目录,环境路径或本地应用目录中找不到DLL,则加载失败。
    即可能出现问题找不到.dll错误
    在这里插入图片描述
    解决方案是:在构建过程中将DLL复制到包含客户端可执行文件的目录中。可以在“生成后事件”添加到项目中,以添加将DLL复制到生成输出目录的命令
    操作: 属性页 - >“生成事件” -> “生成后事件” ->命令行,输入以下命令
    xcopy /y /d “…\MathLibrarySolution(解决方案名称)$(IntDir)MathLibrary.dll(.dll文件名称)” “$(OutDir)”
    在这里插入图片描述

此时运行正常

发布了28 篇原创文章 · 获赞 0 · 访问量 291

猜你喜欢

转载自blog.csdn.net/weixin_37964410/article/details/103699902
今日推荐