实例讲解动态链接库的开发

简介:
静态库是函数和数据被编译进一个二进制文件中(通常扩展名为.lib)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)       动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。在使用动态库的时候,往往提供两个文件:一个引入库和一个DLL。引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。
     动态链接库加载的两种方式:隐式链接,显示加载。关于这两种加载方式的实例说明,请见我的另一篇文章《动态链接库(dll)的调用方法》。以下所有说明均采用隐式链接方式,开发环境为VC
  • 下面说说函数的导出:
创建源文件如下:
_declspec(dllexport) int    add(int a,int b) 

return a+b; 


_declspec(dllexport) int    subtract(int a,int b) 

return a-b; 
}
 
观察编译之后,我们看到了导出函数,只是名字被更改了:
Dump of file dll1.dll 

File Type DLL 

    Section contains the following exports for Dll1.dll 

                     0 characteristics 
        456BD6E2 time date stamp Tue Nov 28 142746 2006 
                0.00 version 
                     1 ordinal base 
                     2 number of functions 
                     2 number of names 

        ordinal hint RVA            name 

                    1        0 0000100A add@@YAHHH@Z 
                    2        1 00001005 subtract@@YAHHH@Z 

    Summary 

                7000 .data 
                1000 .idata 
                3000 .rdata 
                2000 .reloc 
             2A000 .text
 
将刚刚生成动态链接库文件的同一目录下,找到dll1.lib输入库文件,拷贝到我们的工程目录下。此时,我们就可以在应用程序中使用dll1库了。
  #include iostream.h 
extern int add(int,int);     声明这个函数在外部定义 
extern int subtract(int,int); 
_declspec(dllimport) int add(int,int); 
_declspec(dllimport) int subtract(int,int); 
void main(void) 

cout3+5 = add(3,5)endl; 
cout5-3 = subtract(5,3)endl; 
}
  • 下面谈谈关于类的导出:
将整个类都导出:
#ifdef DLL1_API 
#else 
#define DLL1_API _declspec(dllimport) 
#endif 
DLL1_API int add(int,int); 
DLL1_API int subtract(int,int); 
class DLL1_API Point 

public 
void output( int x,int y); 
};
 
如果不想将整个类都导出,只将类的部分共有成员函数导出,则可以采用下面的方法:
#ifdef DLL1_API 
#else 
#define DLL1_API _declspec(dllimport) 
#endif 
DLL1_API int add(int,int); 
DLL1_API int subtract(int,int); 
class DLL1_API Point 

public 
DLL1_API void output( int x,int y); 
void test(); 
};
 
看一下库的导出情况
Dump of file dll1.dll 

File Type DLL 

    Section contains the following exports for Dll1.dll 

                     0 characteristics 
        456BE737 time date stamp Tue Nov 28 153727 2006 
                0.00 version 
                     1 ordinal base 
                     3 number of functions 
                     3 number of names 

        ordinal hint RVA            name 

                    1        0 00001019 add@@YAHHH@Z 
                    2        1 0000101E output@Point@@QAEXHH@Z 
                    3        2 00001014 subtract@@YAHHH@Z 

    Summary 

                7000 .data 
                1000 .idata 
                3000 .rdata 
                2000 .reloc 
             31000 .text
 
上面提到了VC++编译器将函数名字进行了改写,这对于其他编译器来说也许就不是什么好事,因为其他编译器很可能找不到导出的函数,因为名字被改动了。
  • 不改变导出函数名称,保证其他编译器可以使用链接库:
如果不希望改变导出函数的名称,可以加上 extern C 标识
dll1.cpp 
#define DLL1_API extern C _declspec(dllexport) 
#include dll1.h 
int    add(int a,int b) 

return a+b; 

int    subtract(int a,int b) 

return a-b; 


dll1.h 
#ifdef DLL1_API 
#else 
#define DLL1_API extern C _declspec(dllimport) 
#endif 
DLL1_API int add(int,int); 
DLL1_API int subtract(int,int);
 
再看一下导出发现名字没有改变:
Dump of file dll1.dll 

File Type DLL 

    Section contains the following exports for Dll1.dll 

                     0 characteristics 
        456BE969 time date stamp Tue Nov 28 154649 2006 
                0.00 version 
                     1 ordinal base 
                     2 number of functions 
                     2 number of names 

        ordinal hint RVA            name 

                    1        0 0000100A add 
                    2        1 00001005 subtract 

    Summary 

                7000 .data 
                1000 .idata 
                3000 .rdata 
                2000 .reloc 
                2A000 .text
 
extern C
dll1.cpp 
#define DLL1_API extern C _declspec(dllexport) 
#include dll1.h 
int _stdcall    add(int a,int b) 

return a+b; 

int _stdcall    subtract(int a,int b) 

return a-b; 


dll1.h 
#ifdef DLL1_API 
#else 
#define DLL1_API extern C _declspec(dllimport) 
#endif 
DLL1_API int _stdcall add(int,int); 
DLL1_API int _stdcall subtract(int,int);
 
采用_stdcall调用约定后的导出情况:
Dump of file dll1.dll 

File Type DLL 

    Section contains the following exports for Dll1.dll 

                     0 characteristics 
        456BEBDB time date stamp Tue Nov 28 155715 2006 
                0.00 version 
                     1 ordinal base 
                     2 number of functions 
                     2 number of names 

        ordinal hint RVA            name 

                    1        0 00001005 _add@8 
                    2        1 0000100A _subtract@8 

    Summary 

                7000 .data 
                1000 .idata 
                3000 .rdata 
                2000 .reloc 
                2A000 .text
 
采用下述方法可以解决上面的问题 源程序不变,我们创建一个模块定义文件,命名为dll1.def,然后添加到我们的工程中。其内容如下:
LIBRARY Dll1 

EXPORTS 
add 
subtract 
 
LIBRARY Dll1
Dump of file dll2.dll 

File Type DLL 

    Section contains the following exports for Dll2.dll 

                     0 characteristics 
        456BEECE time date stamp Tue Nov 28 160950 2006 
                0.00 version 
                     1 ordinal base 
                     2 number of functions 
                     2 number of names 

        ordinal hint RVA            name 

                    1        0 0000100A add 
                    2        1 00001005 subtract 

    Summary 

                7000 .data 
                1000 .idata 
                3000 .rdata 
                2000 .reloc 
                2A000 .text
这时发现函数名没有改变了。


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/318878,如需转载请自行联系原作者
相关文章
|
人工智能 物联网 机器人
『GitHub项目圈选17』推荐5款本周 火火火 的AI开源项目
『GitHub项目圈选17』推荐5款本周 火火火 的AI开源项目
2038 1
|
运维 监控 Java
内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程)
全网最全的内存溢出CPU占用过高排查文章,包含:问题出现现象+临时解决方案+复现问题+定位问题发生原因+优化代码+优化后进行压测,上线+复盘
3303 5
|
9月前
|
缓存 Java 数据库连接
MyBatis篇-常见配置
本文介绍了 MyBatis 的常见配置及事务管理相关内容。首先概述了 MyBatis 属性加载顺序,方法参数属性优先级最高。接着列举了几个常见配置属性,如 cacheEnabled、lazyLoadingEnabled 等,并说明其作用与默认值。在多环境配置部分,讲解如何通过 SqlSessionFactoryBuilder 指定环境,以及 environments 元素的配置细节。最后讨论了两种事务管理模式:JDBC 和 MANAGED,分别适用于不同场景,并指出在使用 Spring 模块时无需额外配置事务管理器。
|
10月前
|
机器学习/深度学习 数据可视化 算法
YOLOv11改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进
YOLOv11改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进
1644 6
YOLOv11改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进
|
关系型数据库 Java MySQL
从0开始部署阿里云服务器(萌新必看)
搭建阿里云服务器涉及购买、控制台介绍及配置。购买时可选择免费试用或直接购买,根据需求选择计费方式和地区。在服务器控制台,可找到实例并进行远程连接。配置包括Java环境,卸载OpenJDK,下载安装Java,配置环境变量。接着配置Tomcat,下载对应版本,解压并启动,确保防火墙允许8080端口。最后配置MySQL,安装,设置密码,更新远程访问权限。整个过程旨在提供一个基础的云服务器配置指南。
3267 1
|
消息中间件 存储 安全
RabbitMQ Streams 详解
RabbitMQ Streams 详解
1139 0
|
SQL 数据库 HIVE
python链接hive数据库实现增删改查操作
python链接hive数据库实现增删改查操作
654 0
|
数据安全/隐私保护 Windows
Windows子系统WSL使用root用户
Windows子系统WSL使用root用户
365 0
|
固态存储 开发工具 git
mmdetection目标检测训练自己的数据
mmdetection目标检测训练自己的数据