Jche
qwqqqqqq

演练和使用自己的动态链接库C++

2022-02-18 DLL

原文链接https://docs.microsoft.com/zh-cn/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170

演练和使用自己的动态链接库C++

1.在visual studio中创建DLL项目。

2.将导出的函数和变量添加到该DLL。

3.在Visual Studio 中创建一个控制台应用项目。

4.在该控制台应用中使用从DLL导入的函数和变量。

5.运行已完成的应用。

本演练中两个方案,一个生成 DLL,另一个生成客户端应用。 DLL 使用 C 调用约定。 只要平台、调用约定和链接约定匹配,便可从采用其他编程语言编写的应用中进行调用。 客户端应用使用隐式链接 ,其中 Windows 在加载时将应用链接到 DLL。 此链接允许应用调用 DLL 提供的函数,就像调用静态链接库中的函数一样。

创建DLL项目

新建一个MathLibrary.dll项目,可以搜索dll来创建,我这里的版本是visual studio 2022

创建以后就可以在解决方案资源管理器中看到生成的项目和源文件了

接下来我们需要创建一个头文件来声明DLL导出的函数,然后将函数定义添加到DLL,使之具备功能。

1.将头文件添加到DLL

1.在菜单栏中选择项目-添加新项

2.左侧选择Visual C++。选择头文件(.h)。指定MathLibrary.h作为头文件的名称。生成文件。

这里的实例是斐波那契递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

//初始化一个序列
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.向DLL添加实现

1.在解决方案资源管理器中右键点击源文件-添加-新项,创建名为MathLibrary.cpp的新.cpp文件。

编辑该文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "pch.h"
#include <utility>
#include <limits.h>
#include "MathLibrary.h"//为dll定义导出的函数

//dll内部状态变量
static unsigned long long previous_; //之前的值(如果有)
static unsigned long long current_; //当前序列值
static unsigned index_; //当前位置

//初始化一个序列,这个函数必须在任何其他函数之前调用
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_) ||
(UINT_MAX == index_))
{
return false;
}

//特殊情况当序列位置为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_;
}

到这里dll文件就编写完毕了,可以通过点击菜单栏中生成-生成解决方案来查看是否有错误。

这样就成功使用visual studio创建了一个dll。

创建可使用DLL客户端应用

使用visual studio新建一个控制台应用,将项目名称设置为MathClient。(不需要选中将解决方案和项目放在同意目录中)

在源代码中调用MathLibrary函数,项目中必须包括MathLibrary.h文件,将头文件复制到客户端应用项目中,然后将其作为现有项添加到项目中。

在你的默认目录下去找到MathLibrary.h的文件和framework.h的文件复制到MathClient/MathClient的目录下,再去MathLibrary的x64/debug目录下去找到.dll文件和.lib文件,一个是动态链接库,一个是静态链接库,同样复制到MathClient/MathClient的目录下。

完成上述以后,右击解决方案资源管理器中的MathClient,属性-常规-包含目录,添加MathClient/MathClient,这样就可以使用.dll库和头文件了。

然后在MathClient.cpp文件中写入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Mathclient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "MathLibrary.h"
#include "pch.h"
#pragma comment(lib, "MathLibrary.lib") //需要加!!!!!(底下有不加的报错阐述)

int main()
{
//初始化一个斐波那契数列
fibonacci_init(1, 1);
//写出序列值知道溢出
do {
std::cout << fibonacci_index() << ": "
<< fibonacci_current() << std::endl;
} while (fibonacci_next());
//报告溢出前写入的值的计数
std::cout << fibonacci_index() << ": "
<< fibonacci_index() + 1 <<
" Fibonacci sequence values fit in an " <<
"unsigned 64-bit integer." << std::endl;
}

如果头文件上的include没有下划报错什么的就是包含目录路径设置好了)

设置依赖和附加库目录

项目-属性-链接器,右侧框中有一个附加依赖项,输入MathLibrary.lib,添加依赖

项目-属性-链接器-常规, 右侧框中附加库目录,定位到dll文件的库中。

报错提醒)

折腾这个dll的链接其实还挺麻烦的,一开始怎么也弄不对,重新写了很多遍。最后卡在link2019的一个报错上。它提示我main函数中找不到__imp_xxxx(函数)。

这里我先使用dumpbin工具查看dll导出符号,因为是cpp文件,所以有符号被修饰的可能性,导出符号的方法看https://blog.csdn.net/zsc_976529378/article/details/105834611

因为我找到的dumpbin.exe不对劲,所以我是用第二种方法的,但找不到命令提示所以可以自己搭建一个。

1
2
3
4
5
6
7
8
9
从菜单选择“Tools”,然后选择“外部工具”。输入如下:

标题:Visual Studio 命令提示(&C)
命令:%systemroot%\system32\cmd.exe
参数:/K "vsdevcmd.bat -no_logo"
初始目录:D:\Program Files (x86)\Microsoft Visual Studio\2022\Community\Common7\Tools
注意:初始化目录为你安装vs的目录中找

然后点击【应用】,【确认】即可

然后就可以在菜单-工具中找到命令提示了)

查看dll导出符号没有被改,就转眼到了这个

1
__imp_xxxx

是个什么东西,经过google后发现需要将lib文件添加到代码工程中

原文链接:https://blog.csdn.net/HideInTime/article/details/103181629

1
2
3
4
5
6
7
出现字符_imp,说明不是真正的静态库,而是某个动态库的导入库,导入函数和自己不同名,所以加了字符_imp。比如说_imp_GetUserNameA就是GetUserNameA函数。

会报这种错误的原因:

1、说明注册表函数没有相关的lib库,我们需要在MSDN下搜索函数。

2、如果有引入三方库文件,可能存在库编译时和自己的项目编译时的运行库选择不一致(MT/MTd/MD/MDd)。

于是在控制台文件main函数开头加入一行

1
#pragma comment(lib, "MathLibrary.lib")

就可以成功运行了!

Author: John Doe

Link: http://example.com/2022/02/18/DLL/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Unity3D + Frida + Hook
NextPost >
csapp-8
CATALOG
  1. 1. 演练和使用自己的动态链接库C++
    1. 1.1. 创建DLL项目
      1. 1.1.1. 1.将头文件添加到DLL
      2. 1.1.2. 2.向DLL添加实现
    2. 1.2. 创建可使用DLL客户端应用
      1. 1.2.1. 设置依赖和附加库目录
    3. 1.3. 报错提醒)