本文翻译自:Walkthrough: Create and use your own Dynamic Link Library (C++)
这是微软官方的资料,显然针对Windows和Microsoft Visual Studio.
本文包括以下内容:
(1) 通过Visual Studio创建一个DLL项目
(2) 向DLL增加输出的函数和变量。
(3) 用Visual Studio创建一个控制台应用
(4) 在控制台App中引用DLL中的函数和变量。
(5) 运行完整的APP
一个DLL文件按照名称导出变量、函数、资源。一个客户APP引用这个名字去使用那些变量、函数和资源。Windows在加载时或运行时将应用程序中的导入连接到DLL中的导出,而不是在链接时连接它们。Windows需要标准C++编译模型之外的额外信息来建立这些连接。
本文提供了两个Visual Studio的解决方案,一个建立了DLL文件,另一个建立了客户APP。DLL使用C调用规约。它可以从用其他编程语言编写的应用程序中调用,只要平台、调用规约和链接规约匹配。
第一步: 创建DLL项目
选择这个:
在项目中创建一个新的头文件,在其中写入类似于这样的内容:
// MathLibrary.h - Contains declarations of math functions
#pragma 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 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, ...
// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any 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.
// Returns 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 current value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();
请注意文件顶部的预处理器语句。DLL项目的新项目模板将_EXPORTS添加到定义的预处理器宏中。在这个例子中,Visual Studio在构建MathLibrary DLL项目时定义MATHLIBRARY_EXPORTS。
当定义MATHLIBRARY_EXPORTS宏时,MATHLIBRARY_API宏会在函数声明上设置__declspec(dllexport)修饰符。这个修饰符告诉编译器和链接器从DLL中输出函数或变量以供其他应用程序使用。
第二步: 增加对DLL的实现
在之前的头文件的基础上,编写类似于下面这样的.cpp文件:
// MathLibrary.cpp : Defines 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 current_; // Current sequence value
static unsigned index_; // 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
}
// Produce the next value in the sequence.
// Returns 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)
{
// otherwise, 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 index position in the sequence.
unsigned fibonacci_index()
{
return index_;
}
点击生成—>生成解决方案,得到类似于下面的结果:
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 ==========
更新: 再试着看看后面的内容。
第三步: 创建一个使用这个DLL的客户端APP
当你创建一个DLL时,考虑客户端如何使用它。为了调用DLL输出的函数或访问DLL输出的数据,在编译时间客户端源代码必须有可用声明。在链接时,链接器需要信息来解析函数调用或数据访问。DLL在一个导入库(一个包含如何查找函数和数据的信息的文件)中提供这些信息,而不是实际的代码。在运行时,DLL必须在操作系统可以找到的位置对客户端可用。
不论是你自己的或来自一个第三方,你的客户端APP项目需要一些信息以便使用DLL。它需要找到声明DLL导出的头文件、链接器的导入库和DLL本身。一个方法是把所有这些文件复制到客户端项目。对于在客户端开发过程中不太可能更改的第三方dll,这种方法可能是使用它们的最佳方式。然而,当你也构建DLL时,最好避免重复。
为避免代码不同步,我们建议您将客户端项目中的包含路径设置为直接从DLL项目包含DLL头文件。另外,在客户端项目中设置库路径,以包含来自DLL项目的DLL导入库。最后,将构建的DLL从DLL项目复制到您的客户机构建输出目录中。此步骤允许您的客户端应用程序使用您构建的相同DLL代码。