创建并使用自己的DLL文件(动态链接库)
本文创建一个实现一些数学函数的DLL。然后,创建一个控制台应用程序,使用DLL中的函数。您还将获得一些在窗口动态链接库中使用的编程技术和约定的介绍。
本文任务:
1.在Visual Studio中创建一个DLL项目。
2. 将导出的函数和变量添加到动态链接库。
3. 在Visual Studio中创建控制台应用程序项目。
4. 在控制台应用程序中使用从DLL导入的函数和变量。
5. 运行完成的应用程序。
像静态链接库一样,DLL按名称导出变量、函数和资源。客户端应用程序导入名称以使用这些变量、函数和资源。
与静态链接库不同,Windows在加载时或运行时将应用程序中的导入 连接到DLL中的导出,而不是在链接时连接它们。Windows需要不属于标准C++编译模型的额外信息来建立这些连接。MSVC编译器实现了一些特定于微软的C++扩展来提供这些额外的信息。我们边走边解释这些扩展。
创建两个Visual Studio解决方案;一个构建DLL,一个构建客户端应用程序。DLL使用C调用约定。只要平台、调用约定和链接约定匹配,就可以从用其他编程语言编写的应用程序中调用它。客户端应用程序使用隐式链接,在加载时,窗口将应用程序链接到动态链接库。这种链接让应用程序调用DLL提供的函数,就像静态链接库中的函数一样。
本演练不涵盖一些常见情况。代码没有显示其他编程语言对c++ dll的使用。它没有展示如何创建一个只包含资源的动态链接库,或者如何使用显式链接在运行时而不是在加载时加载动态链接库。放心,这些都可以用MSVC和Visual Studio来做。
条件:
- 运行微软视窗7或更高版本的计算机。为了获得最佳的开发体验,推荐最新版本的Windows。
- Visual Studio的副本。有关如何下载和安装Visual Studio的信息,请参见安装Visual Studio。运行安装程序时,请确保检查了使用C++的桌面开发工作负载。如果您在安装Visual Studio时没有安装此工作负载,请不要担心。您可以再次运行安装程序并立即安装。
- 了解使用Visual Studio集成开发环境的基础知识。如果你以前用过Windows桌面应用,你可能会跟上。有关介绍,请参见Visual Studio IDE功能教程。
- 对C++语言基础的理解。当然,我们不会做太复杂的事情。
总的流程概览:
在Visual Studio 2019中创建DLL项目
- 在菜单栏上,选择文件>新建>项目以打开创建新项目对话框。
- 在对话框顶部,将语言(language)设置为C++,将平台(Platform)设置为窗口(Windows),并将项目类型(Project type)设置为库(Library)。
- 从项目类型的筛选列表中,选择动态链接库,然后选择Next。
- 在“Configure your new project ”页面中,在“Project name box”框中输入“MathLibrary ”以指定项目的名称。保留默认的位置和解决方案名称值。设置解决方案以创建新的解决方案。取消选中将解决方案和项目放在同一目录中(如果已选中)。
- 创建解决方案时,您可以在Visual Studio的“解决方案资源管理器”窗口中看到生成的项目和源文件。
现在,这个动态链接库做的不多。接下来,您将创建一个头文件来声明DLL导出的函数,然后将函数定义添加到DLL中,使其更加有用。
向动态链接库添加头文件
- 要为您的功能创建头文件,请在菜单栏上选择“项目”>“添加新项目”。
- 在“添加新项”对话框的左窗格中,选择“Visual C++”。在中间窗格中,选择Header File (.h)。指定MathLibrary.h作为头文件的名称。
- 选择“添加”按钮生成一个空白头文件,该文件将显示在新的编辑器窗口中。用以下代码替换头文件的内容:
//MathLibrary.h -Contains decalrations of math functions
#paragma once #ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif
//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 sequenc is initialized F(0) =1, F(1) = 1,
//then the realtion produces the well-known Fibonacci
//sequence :1,1,2,3,5,8,13,21,34,...
//Initialize a Fibonacci relation sequence
//such that F(0)=a,F(1)=b.
//This function must be called before any by other function.
extern "C" MATHLIBRARY_API void fibonacci_init(const unsigned long long a ,const unsigned long long b);
//produce the next value in the sequence .
//return true on success and updates current value and index;
//false on overflow, leaves current value and index unchanged.
extern "C" MATHLIBRARY_API bool fibonacci_next();
//get the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
//get the position of the curren value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();
这个头文件声明了一些函数来产生一个广义的斐波那契序列,给定两个初始值。调用fibonacci_init(1,1)会生成熟悉的斐波那契数列。
注意,文件顶部的预处理语句。DLL项目的新项目模板将PROJECTNAME_EXPORTS添加到已定义的预处理器宏中。在本例中,Visual Studio在构建您的MathLibraryDLL项目时定义了MATHLIBRARY_EXPORTS。
当MATHLIBRARY_EXPORTS宏被定义时,MATHLIBRARY_API宏在函数声明中设置__declspec(dllexport)修饰符。这个修饰符告诉编译器和链接器从动态链接库导出一个函数或变量供其他应用程序使用。当MATHLIBRARY_EXPORTS未定义时,例如,当头文件被客户端应用程序包含时,MATHLIBRARY_API将__declspec(dllimport)修饰符应用于声明。此修饰符优化了应用程序中函数或变量的导入。
向动态链接库添加implementation
- 在解决方案资源管理器中,右键单击“ Source Files”节点,然后选择“添加”>“新建项目”。创建新的。名为MathLibrary.cpp的cpp文件,与您在上一步中添加新头文件的方式相同。
- 在编辑器窗口中,选择MathLibrary.cpp的选项卡(如果它已经打开)。如果没有,在解决方案Solution Explorer中,双击“ MathLibrary ”项目的“Source Files ”文件夹中的“ MathLibrary.cpp ”。
- 在编辑器中,用以下代码替换MathLibrary.cpp文件的内容:
//MathLibrary.cpp:Define the exported functions for the dll.
#include"pch.h"//use stdafx.h in visual studio 2017 and earlier
#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 curreut_;//current sequence value
static unsignedindex_;//current seq.position//initialize a Fibonacci relation sequence
//such that F(0) =a ,F(1)=b.
//this function must be called before any other function
void fibonacci_init(const unsigned long long a, const unsigned long long b)
{index_ = 0;
current_ =a;
previous_=b;//see special case when initialized
}
//ptoduce the next value in the sequence.
//return true on success,false on overflow.
bool fibonacci_next()
{//check to see if we'd overflow result or position
if ((ULLONG_MAX -previous_ < current_) ||(UINT_MAX ==index_)){return false;}
//special case when index==0,just return b value
if(index_>0)
{//othwewise ,calculate next sequence value
previous_+=current_;
}
std::swap(current_, previous_);
++index_;
return true;
}//get the current value in the sequence.
unsigned long long fibonacci_current(){return current_;}
//get the current indec position in the sequence.
unsigned fibonacci_index()
{return index_;}
要验证到目前为止一切正常,请编译动态链接库。若要编译,请选择菜单栏上的“构建”>“构建解决方案”。DLL和相关的编译器输出被放在一个名为Debug的文件夹中,该文件夹位于解决方案文件夹的正下方。如果您创建一个发布版本,输出将被放在一个名为“发布”的文件夹中。输出应该如下所示:
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
以上已经使用Visual Studio创建了一个DLL!接下来,您将创建一个使用DLL导出的函数的客户端应用程序。(以上写了这么多,其实操作的话 复制粘贴就那么几步哈哈哈)
创建一个使用动态链接库的客户端应用程序
当你创建一个动态链接库时,想想客户端应用程序会如何使用它。要调用函数或访问由DLL导出的数据,客户端源代码必须具有编译时可用的声明。在链接时,链接器需要信息来解析函数调用或数据访问。动态链接库在导入库中提供这些信息,导入库是一个包含如何查找函数和数据的信息的文件,而不是实际的代码。在运行时,DLL必须在操作系统可以找到的位置对客户端可用。
无论是您自己的还是来自第三方的,您的客户端应用程序项目都需要几条信息来使用DLL。它需要找到声明DLL导出的头、链接器的导入库以及DLL本身。一种解决方案是将所有这些文件复制到您的客户端项目中。对于在客户端开发过程中不太可能改变的第三方dll,这种方法可能是使用它们的最佳方式。但是,当您也构建DLL时,最好避免重复。如果您制作正在开发的DLL文件的本地副本,您可能会意外地在一个副本中更改头文件,而不是另一个副本,或者使用过期的库。
为了避免代码不同步,我们建议您将客户端项目中的包含路径设置为直接包含DLL项目中的DLL头文件。此外,在客户端项目中设置库路径,以包含来自DLL项目的DLL导入库。最后,将构建的DLL从DLL项目复制到您的客户端构建输出目录中。此步骤允许您的客户端应用程序使用您构建的相同DLL代码。
在Visual Studio中创建客户端应用程序
- 在菜单栏上,选择文件>新建>项目以打开创建新项目对话框。
- 在对话框顶部,将语言设置为C++,将平台设置为窗口,并将项目类型设置为控制台。
- 从项目类型的筛选列表中,选择控制台应用程序,然后选择下一步。
- 在“配置新项目”页面中,在“项目名称”框中输入“MathClient”以指定项目的名称。保留默认的位置和解决方案名称值。设置解决方案以创建新的解决方案。取消选中将解决方案和项目放在同一目录中(如果已选中)。
- 选择“创建”按钮创建客户端项目。
为您创建了一个最小的控制台应用程序项目。主源文件的名称与您之前输入的项目名称相同。在这个例子中,它被命名为MathClient.cpp。您可以构建它,但是它还没有使用您的DLL。
接下来,要在源代码中调用MathLibrary函数,您的项目必须包含MathLibrary.h文件。您可以将此头文件复制到您的客户端应用程序项目中,然后将其作为现有项目添加到项目中。这种方法对于第三方库来说是一个很好的选择。但是,如果您同时为您的DLL和客户端处理代码,头文件可能会不同步。要避免此问题,请在项目中设置“附加包含目录”路径,以包含原始标题的路径。
将动态链接库头添加到包含路径中
- 右键单击解决方案资源管理器中的“MathClient”节点,打开“属性页(Property Pages)”对话框。
- 在配置下拉框中,选择所有配置(如果尚未选择)。
- 在左窗格中,选择配置属性> C/C++ >常规。
- 在属性窗格中,选择“附加包括目录”编辑框旁边的下拉控件,然后选择“编辑”。
- 在“附加包括目录”对话框的顶部窗格中双击以启用编辑控件。或者,选择文件夹图标来创建新条目。
- 在编辑控件中,指定MathLibrary.h头文件位置的路径。您可以选择省略号(…)控件浏览到正确的文件夹。
您也可以输入从客户端源文件到包含DLL头文件的文件夹的相对路径。如果您按照指示将客户端项目放在一个独立于DLL的解决方案中,则相对路径应该如下所示:
…\MathLibrary\MathLibrary
如果您的DLL和客户端项目在同一个解决方案中,相对路径可能如下所示:
…\MathLibrary
当DLL和客户端项目在其他文件夹中时,调整相对路径以匹配。或者,使用省略号控件浏览文件夹。
在“附加包含目录”对话框中输入头文件的路径后,选择“确定”按钮。在“属性页”对话框中,选择“确定”按钮保存更改。
现在,您可以包含MathLibrary.h文件,并在客户端应用程序中使用它声明的函数。使用以下代码替换MathClient.cpp的内容:
//MathClient.cpp:Client app for MathLibrary DLL.
//#inclue"pch.h"Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include"MathLibrary.h"
int main()
{//Initialize a Fibonacci relation sequence.
fibonacci_init(1,1);
//write out the sequence values untill overflow.
do{std::cout <<fibonacci_index()<<":"<<fibonacci_current()<<std::endl;
}while (fibonacci_next());
//report count of values written before overflow.
std::cout<<fibonacci_index() +1<<"Fibonacci sequence values fit in an"<<"unsigned 64-bit inter."<<std::endl;
}
这段代码可以编译,但不能链接。如果您现在构建客户端应用程序,错误列表会显示几个LNK2019错误。这是因为您的项目缺少一些信息:您还没有指定您的项目依赖于MathLibrary.lib库。此外,您还没有告诉链接器如何找到MathLibrary.lib文件。
要解决此问题,您可以将库文件直接复制到客户端应用程序项目中。链接器会自动找到并使用它。但是,如果库和客户端应用程序都在开发中,这可能会导致一个副本中的更改不会显示在另一个副本中。为了避免这个问题,您可以设置“附加依赖项”属性来告诉构建系统您的项目依赖于MathLibrary.lib。此外,您还可以在项目中设置一个附加库目录路径,以便在链接时包含原始库的路径。
将DLL导入库添加到项目中
- 右键单击解决方案资源管理器(Solution Explorer)中的“MathClient”节点,然后选择“属性”以打开“属性页”对话框。
- 在配置下拉框中,选择所有配置(如果尚未选择)。它确保任何属性更改都适用于调试和发布版本。
- 在左窗格中,选择配置属性>链接器>输入。在属性窗格中,选择“附加依赖项”编辑框旁边的下拉控件,然后选择“Edit”。
- 在“附加依赖项”对话框中,将“MathLibrary.lib”添加到顶部编辑控件的列表中。
5.选择“确定”返回“属性页”对话框。
6.在左窗格中,选择配置属性>链接器>常规。在属性窗格中,选择“附加库目录”编辑框旁边的下拉控件,然后选择“编辑”。
7.在“附加库目录”对话框的顶部窗格中双击以启用编辑控件。在编辑控件中,指定MathLibrary.lib文件位置的路径。默认情况下,它位于DLL解决方案文件夹下名为调试的文件夹中。如果您创建了一个发布版本,该文件将被放在一个名为“发布”的文件夹中。您可以使用$(IntDir)宏,以便链接器可以找到您的DLL,无论您创建哪种版本。如果您按照指示将客户端项目放在一个独立于DLL项目的解决方案中,则相对路径应该如下所示:
…\MathLibrary$(IntDir)
如果您的DLL和客户端项目在其他位置,请调整相对路径以匹配。
8.在“附加库目录”对话框中输入库文件的路径后,选择“确定”按钮返回“属性页”对话框。选择“确定”保存属性更改。
您的客户端应用程序现在可以成功编译和链接,但它仍然没有运行所需的一切。当操作系统加载您的应用程序时,它会查找MathLibrary DLL。如果它在某些系统目录、环境路径或本地应用程序目录中找不到DLL,加载将失败。根据操作系统的不同,您会看到如下错误消息:
避免此问题的一种方法是将DLL复制到包含客户端可执行文件的目录中,作为构建过程的一部分。您可以向项目中添加一个后期生成事件,以添加一个将DLL复制到生成输出目录的命令。此处指定的命令仅在DLL丢失或已更改时才复制它。它根据您的生成配置,使用宏在调试或发布位置之间复制。
在后期生成事件中复制DLL(这步很重要,以后其他项目在添加dll文件的时候也可以借鉴,反正我是这样的,个人见解)
- 右键单击解决方案资源管理器中的“MathClient”节点,然后选择“属性”以打开“属性页”对话框。
- 在配置下拉框中,选择所有配置(如果尚未选择)。
- 在左窗格中,选择配置属性>生成事件>生成后事件。
- 在属性窗格中,选择命令行字段中的编辑控件。如果您按照说明将客户端项目放在与DLL项目不同的解决方案中,请输入以下命令:
xcopy /y /d “…\MathLibrary$(IntDir)MathLibrary.dll” “$(OutDir)”
如果您的DLL和客户端项目在其他目录中,请更改DLL的相对路径以匹配。
5.选择“确定”按钮保存对项目属性的更改。
现在,您的客户端应用程序拥有了构建和运行所需的一切。通过选择菜单栏上的构建>构建解决方案来构建应用程序。根据您的Visual Studio版本,Visual Studio中的“输出”窗口应该类似于下面的示例:
1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
您已经创建了一个调用DLL中函数的应用程序。现在运行您的应用程序,看看它能做什么。在菜单栏上,选择调试>不调试启动。Visual Studio打开一个命令窗口,让程序在其中运行。输出的最后一部分应该如下所示:
按任意键关闭命令窗口。
现在您已经创建了一个动态链接库和一个客户端应用程序,您可以进行实验了。尝试在客户端应用程序的代码中设置断点,并在调试器中运行该应用程序。看看当你进入一个库调用时会发生什么。向库中添加其他函数,或者编写另一个使用您的DLL的客户端应用程序。
部署应用程序时,还必须部署它使用的dll。最简单的方法就是把你构建的或者你从第三方获得的动态链接库和你的应用放在同一个目录下。这就是所谓的应用本地部署。
创建并使用自己的DLL文件(动态链接库)相关推荐
- php 打开动态链接,php调用com组件-dll文件(动态链接库)
什么是COM? COM(Component Object Model)组件对象模型,是一种跨应用和语言共享二进制代码的方法.是位于DCE RPC上部的对象指向层(关联服务)定义公共的调用协定以允许用不 ...
- 如何注册全部DLL文件以及DLL简要说明
将您下载的 "*. DLL" 文件复制到 "C:\Windows\system32\" 系统目录下然后按 "Win键+R" 或单击 &quo ...
- C#中创建DLL(动态链接库)及其使用
一.DLL 与应用程序 动态链接库(也称为 DLL ,即为" Dynamic Link Library "的缩写)是 Microsoft Windows 最重要的组成要素之一,打开 ...
- c 调用c语言写的dll文件路径,手把手教你用C/C++语言创建及调试动态库DLL程序
引子 动态链接库DLL文件不仅可以实现代码.资源和数据的共享,同时也可以对源代码起保护作用,对于开发者来讲,DLL的生成及调试是程序员必须掌握的一种技术,下面通过一个具体的例子,演示使用C/C++语言 ...
- 利用C语言创建和使用DLL文件
有感于讲C语言的DLL文件的文章很少,自己查了半天,写了这么个非常简单的教程.自己也是摸C语言不久,依然感觉处于编程苦手的阶段. 1)为什么使用DLL文件 C语言复用代码有很多 ...
- 使用vs2008制作dll文件,生成动态链接库
转自:http://blog.csdn.net/howard_liu1314/article/details/7862326 1.制作dll文件 vs2008中,File > New P ...
- 怎么创建dllwenjian_如何创建DLL文件
动态链接库(DLL)是从C语言函数库和Pascal库单元的概念发展而来的.所有的C语言标准库函数都存放在某一函数库中.在链接应用程序的过程中,链接器从库文件中拷贝程序调用的函数代码,并把这些函数代码添 ...
- VS2017创建DLL文件并调用
项目中甲方需要我把一个写好的函数打包成DLL,因为之前没有做过,中间也遇到了很多问题,比如找不到创建的DLL文件.生成了DLL但是没有生成lib文件等.因此在创建完成并成功测试后写了这篇博客,希望能帮 ...
- linux运行dll文件命令,linux下的动态链接库(DLL)
一.公约 1. 库的命名习惯 一个linux DLL 有三个不同名字的文件组成 soname 文件 lib + 链接库名字 + .so + .版本号 每当链接库接口改变时都递增版本号.soname 文 ...
最新文章
- python3基本知识_Python3 - 基础知识、基本了解
- 使用brew安装Logstash(Mac)
- DBSCAN算法理论和Python实现
- [转]游戏中各种性能优化方法(不断更新)
- [洛谷P1951]收费站_NOI导刊2009提高(2)
- linux 虚函数调用性能,C++对象布局及多态实现探索之虚函数调用
- OpenCV与图像处理学习一——图像基础知识、读入、显示、保存图像、灰度转化、通道分离与合并
- 获取矩阵元素的方法 4种方法 B(1,2) B(9) B(sub2ind(size(B),3,4))
- poj japan 数状数组解决逆序数
- xUtils3 注解模块
- WPS显示无法创建对象,请确认对象已在系统注册表中注册
- 在android下使用i2c tools
- 天使、A轮、B轮……公司不同阶段估值方法大全
- SpringBoot整合银联支付
- 数据结构资源视频地址
- excel中表格行高最大值是多少?如果超过了怎么调整?
- (转!)利用Keras实现图像分类与颜色分类
- 关于av_freep
- jQuery是什么?和它的优缺点
- SegmentFault 技术周刊 Vol.4 - 这份 Android 有点甜