动态链接库(二)--动态链接库的创建

2023-11-13

开发环境

系统: Win10企业版 64位
vs版本: Microsoft Visual Studio 2010, 版本10.0

Dll项目创建

为从头了解dll项目中各文件的来源, 这里暂不使用vs新建项目列表中的动态链接库(DLL)向导, 选择创建一个空项目.

打开VS2010 -> 新建项目 -> win32控制台应用程序 -> 选中DLL类型 -> 空项目, 例这里创建了一个Dll1的空项目.
创建一个空项目
然后右键源文件添加Dll1…cpp源文件,我们在该文件中封装函数。
添加Dll1.cpp源文件
添加后如图:
添加Dll1.cpp文件后
然后在Dll1.cpp源文件中封装两个简单的函数:
封装简单函数
编译运行后, 右键Dll1.cpp -> 打开文件所在位置, 返回上级目录, 进入Debug目录下, 可以看到刚生成的Dll1.dll文件:
首次生成Dll1.dll文件
注意: 这里没有生成引入库文件(.lib文件)

生成dll后, 可以发现这里没有任何关于该dll的说明, 比如它怎么用, 有哪些可供外部调用的函数等.

为了查看一个DLL中有哪些导出函数,可以利用Visual Studio提供的dumpbin命令行工具来实现。

有一点需要知道的是:如果应用程序想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数。

该工具一般在VS的安装目录下, 命名为dumpbin.exe, 我的安装目录在E盘, 路径如下:
dumpbin工具
因为后面我们会在自己的dll项目的文件目录下使用dumpbin, 因此需要将该路径配置到系统的PATH环境变量中去,使得我们可以在任何目录使用该命令。
配置dumpbin环境变量
Win+r打开控制台,切换到Dll1.dll所在目录。或者直接在该目录下Shift+鼠标右键打开控制台。

调用如下命令:dumpbin –exports Dll1.dll, 可以看到如下信息:
dumpbin首次查看dll文件
发现并没有看到任何与函数(add或subtract)有关的信息,这说明Dll1.dll目前没有导出函数。

因为Dll1.cpp中并没有显式的将两个函数声明为导出函数,在函数声明前加_declspec(dllexport)声明符可将该函数声明为动态链接库的导出函数。

修改Dll1.cpp中的代码,如下:
声明导出函数
当然_declspec(dllexport) 也可放在返回类型和函数名中间:
声明导出函数2
重新生成该动态链接库项目,可以看到如下输出信息:
生成dll
至此, 就已经是一个简单生成动态链接库的的DLL项目了.

注意这里生成了Dll1.lib 和 Dll1.exp两个文件, 其中Dll1.lib就是前面提到的引入库文件

Dll1.exp是一个输出库文件,因为后续都没涉及该文件,所以这里不再扩展。

紧接着后面也生成了Dll1.dll文件。
再次使用dumpbin命令查看Dll1.dll导出函数的信息,如下:
dumpbin查看dll
可以看到,这时多出了一些输出信息:

Ordinal hint RVA name
1 0 0001107D ?add@@YAHHH@Z = @ILT+120(?add@@YAHHH@Z)
2 1 00011069 ?subtract@@YAHHH@Z = @ILT+100(?subtract@@YAHHH@Z)

ordinal”列出的信息:“1” 和 “2”是导出函数的序号;
hint”列出的数字是提示码;
RVA”列出的地址值是导出函数在DLL模块中的位置,也就是说,通过该地址值,可以在DLL中找到它们;
name”列出的是导出函数的名称,可以看到这些名称和我们在Dll1.cpp中定义的不同,例我们定义的add函数在此处却显示为:?add@@YAHHH@Z

这是因为C++支持函数重载,也是为了区分多个DLL文件中可能重名的函数,在编译链接时,C++会按照自己的规则篡改函数的名称,这一过程称为“名字改编”,或也称为”名字粉碎”。

名字改编

在编译链接时,C++会按照自己的规则篡改函数的名称,这一过程称为“名字改编” 或 ”名字粉碎”。

上面提到, 名字改编是为了应对 C++的函数重载机制 以及 多个Dll中重名函数 的情况, 虽都会发生名字改编, 但改编的规则却不仅相同, 例不同的编译器或调用约定改编规则会有明显差异.

这里以C 和 C++ 编译环境下, 不同调用约定的情况举例说明:

①C编译时名字改编规则

  • _stdcall 调用约定: 在导出函数名前加一个下划线前缀, 在导出函数名后加一个@, @后接其所有参数的总字节数, 格式为_functionName@number
  • cdecl 调用约定: 仅在导出函数名前加一个下划线()前缀, 格式为_functionName
  • _fastcall调用约定: 在导出函数名前加一个@, 函数名后也加一个@, 然后第二个@后接其所有参数的总字节数, 格式为@functionName@number

②C++编译时名字改编规则

  • _stdcall 调用约定: 以 ? 标识函数名的开始, 后跟函数名, 函数名后以 @@YG 标识参数表的开始, 后跟参数类型, 参数类型以以下代号表示:
    X: void
    D: char
    E: unsigned char
    F: short
    H: int
    I: unsigned int
    J: long
    K: unsigned log
    M: float
    N: double
    _N: bool
    PA: 表示指针, PA后会带代号, 表明指针的类型. 如果相同类型的指针连续出现, 以 0 代替重复, 一个 0 表示一次重复, 注意只针对指针类型.

    参数表的第一项为该函数的返回值类型, 其后依次为参数的类型.

    参数表后以 @Z 标识整个名字的结束, 如果该函数无参数, 则以 Z 标识结束.

    例:
    void _declspec(dllexport) _stdcall test(int a, int b);
    改编后的函数名为: ?test@@YGXHH@Z
    说明: 以?标识函数名开始, @@YG标识参数表开始, 参数表中第一项为返回类型void(对应X), 后跟第一个参数类型int(对应H), 第二个参数类型同一个参数类型一致, 但不是指针类型, 因此这里H标识int, 最后以@Z 标识整个名字的结束

    int _declspec(dllexport) _stdcall add(int* a, int* b, int* c, char d);
    改编后的函数名为: ?add@@YGHPAH00D@Z
    说明: 依旧以?标识函数名开始, @@YG标识参数表开始, 参数表中第一项为返回类型int(对应H), 后跟第一个参数类型int*(对应PA-指针, H指针类型), 因为第二个参数类型也为int*, 因此这里以一个 0 表示重复, 第三个参数类型依旧是int*, 因此后再加一个 0 表示重复指针类型, 最后一个参数类型为char(对应D), 也依旧以 @Z 结束整个命名.

  • _cdecl 调用约定: 规则同上面的_stdcall调用约定, 只是参数表的开始标识由上面的 @@YG 变为 @@YA

  • _fastcall 调用约定: 规则同上面的_stdcall调用约定, 只是参数表的开始标识由上面的 @@YG 变为 @@YI

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态链接库(二)--动态链接库的创建 的相关文章

随机推荐

  • Centos MySql安装,保姆级安装教程

    Centos MySql安装 保姆级安装教程 1 删除原有的mariadb 不然mysql装不进去 查询MAriaDB命令 rpm qa grep mariadb 删除 rpm e nodeps mariadb libs 5 5 60 1
  • pip与conda有什么区别,常用命令有哪些?

    文章目录 pip与conda有什么区别 常用命令有哪些 1 pip与conda 2 pip常用命令 3 conda常用命令 pip与conda有什么区别 常用命令有哪些 1 pip与conda pip是Python 包管理工具 该工具提供了
  • 关于Linux/Ubuntu重置用户名密码

    Step1 重启 往死里按Esc或等启动后嗯Enter Step2 成功后会进入如下界面 这一步后如果你已经知道root密码 请直接跳到Step8 Step3 在菜单Ubuntu这摁 e 进入编辑模式 对标出行 做出如下修改 Step4 根
  • 零信任架构简介

    2021 年被誉为网络安全元年 种种因素极大的驱动了零信任成为安全新风口 零信任也无疑成为了整个安全圈包括网络安全领域最热门的词汇之一 什么是零信任 零信任既不是单一的产品 也不是单一的技术 它是一种安全理念以及安全架构 核心原则是持续验证
  • SV中program & module

    相同之处 1 和module相同 program也可以定义0个或多个输入 输出 双向端口 2 一个program块内部可以包含0个或多个initial块 generate块 specparam语句 连续赋值语句 并发断言 timeunit声
  • GPS 的PPS

    校准RTC时间的方法 首先需要一个准确的外部信号 比如GPS来的秒信号 或者其它很准确的信号 然后通过定时器来测量RTC的晶振误差 然后再对该误差进行校准 面接收机GPS的秒脉冲精度 也就是相邻两个秒脉冲上升沿的间隔精度能到100ns 授时
  • HTML+CSS+JS制作【飞机大战】小游戏(键盘版和鼠标版)

    文章目录 一 效果演示 设计思路 二 鼠标版飞机大战代码展示 1 HTML结构代码 2 CSS样式代码 3 JavaScript代码 js js文件 plane js文件 三 键盘版飞机大战代码展示 1 HTML结构代码 2 CSS样式代码
  • eclipse下maven打包失败(Please ensure you are using JDK 1.4 or above and not ......

    在eclipse下用maven编译时 可能会失败 报出以下提示 ERROR Unable to locate the Javac Compiler in ERROR C Program Files Java jre1 8 0 72 lib
  • 【ABviewer从零开始教学查看器篇①】3D查看器和3D剖面板

    ABViewer是一款高质量 高效率 低成本的多功能设计及工程文档管理工具 能为您提供全面的专业的浏览及编辑功能 同时支持30多种光栅和矢量图形格式 在小编看来 ABViewer是一款非常简单且实用的CAD文档查看与编辑器 对于使用小白可能
  • 华为云计算相关知识点

    云计算离不开网络基础设施 云计算中的网络分为不同的平面 管理平面 负责整个系统的监控 操作维护 系统配置 系统加载 告警上报 和虚拟机管理 创建 删除虚拟机 虚拟机调度 等 存储平面 主要为存储系统提供通信平面 并未虚拟机提供存储资源 用于
  • 你的数据隐私值多少钱?也许已有答案了

    全文共6032字 预计学习时长12分钟 图片来源 Timo Lenzen 对于一些大型科技公司来说 这一年侵犯用户隐私付出的代价变高了 未来还会更高吗 今年7月 脸书在受到有关泄露数亿用户数据隐私的指控后 同意缴纳50亿美元的罚金 同一周内
  • 【TOOLS】Python 3利用SMTP进行邮件Email自主发送

    作者 Che Hongshu 来源 AI蜗牛车 ID AI For Car 一 前言 利用Python进行邮件的发送 这个功能自我感觉主要应用于检测或者报告之类 我两次运用这个功能 第一次用在主要发送实时的数据给一个邮箱 第二次用是检测挂在
  • VS调试:函数断点与数据断点

    断点 是Debug过程中最常用的功能 关于断点VS还有很多高级功能 本文使用的是VS2017 介绍函数断点与数据断点的使用场景以及使用方法 1 普通断点 普通断点是最常接触的断点 VS中 在代码行左边栏灰色区域点击 或者把光标放在某代码行按
  • 使用Python编写Maya脚本插件批量导入Obj文件

    最近开发中遇到需要使用Python语言编写Maya脚本 要求使用脚本选择某一磁盘路径 脚本根据路径自动导入路径与子目录下的所有OBJ文件 并重命名它们 在Maya中 有自带的脚本编辑器供我们使用 这使得我们编写代码非常轻松 打开脚本编辑器
  • Installation did not succeed. The application could not be installed: INSTALL_FAILED_USER_RESTRICTED

    当我们第一次在我们的手机上 也就是物理设备上 运行我们的写好的安卓应用程序时可能会报以下错误 Session app Installation did not succeed The application could not be ins
  • 互斥锁的实现细节

    首先 一个互斥锁要实现什么功能 一个互斥锁需要有阻塞和唤醒功能 实现阻塞和唤醒功能需要哪些要素 需要有一个标记锁状态的state变量 需要记录哪个线程持有了锁 需要有一个队列维护所有的线程 另外 state和队列中为了实现线程安全都用到了C
  • Java - 将base64编码解码成图片

    为了方便测试 我们可以使用一个图片编码网站 将图片进行base64编码 解密的代码如下 public static String generateImage String base64 String path 解密 try String s
  • 计算机视觉(十六):目标检测概述

    1 什么是目标检测 目标检测 Object Detection 的任务是找出图像中所有感兴趣的目标 物体 确定它们的类别和位置 例子 确定某张给定图像中是否存在给定类别 比如人 车 自行车 狗和猫 的目标实例 如果存在 就返回每个目标实例的
  • 配置哨兵监控Redis运行情况

    Redis的主从架构 如果master发现故障了 还得手动将slave切换成master继续服务 手动的方式容易造成失误 导致数据丢失 那Redis有没有一种机制可以在master和slave进行监控 并在master发送故障的时候 能自动
  • 动态链接库(二)--动态链接库的创建

    开发环境 系统 Win10企业版 64位 vs版本 Microsoft Visual Studio 2010 版本10 0 Dll项目创建 为从头了解dll项目中各文件的来源 这里暂不使用vs新建项目列表中的动态链接库 DLL 向导 选择创