欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在VS中创建和使用动态库

程序员文章站 2022-03-22 14:40:33
...

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

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

创建一个DLL项目

1. 在Vs2017中创建DLL项目

1.1 在菜单栏中,选择 “文件” ->“新建”->“项目”,打开“ 新建项目”对话框。
1.2 选择 “Visual C++”->“Windows桌面”->“动态链接库”,设置文件名称及解决方案名称,选择确定按钮。
在VS中创建和使用动态库
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. 在菜单栏上,选择 “生成”->“生成解决方案”,编译器会创建一共可供其它程序使用的动态库。
    在VS中创建和使用动态库

创建使用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 新建项目
    在VS中创建和使用动态库

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

2.1 在菜单栏,选择“项目”,在MathClient的“ 属性页”对话框中,展开“ 配置属性”节点,再展开“ C / C ++”节点,然后选择“ 常规”。在“附加包含目录”,指定MathLibrary.h头文件的位置的路径,或浏览它【浏览到项目路径下即可】。
在VS中创建和使用动态库
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
    在VS中创建和使用动态库

  3. 属性页 - >“链接器” -> “常规” ->“附加库目录”,添加MathLibrary.lib所在目录
    在VS中创建和使用动态库
    或相对路径…\MathLibrarySolution(解决方案名称)$(IntDir)
    在VS中创建和使用动态库

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

此时运行正常

相关标签: Visual Studio