• 动态链接库 DLL


    动态链接库DLL

    不使用时不会有任何作用,只有在其他模块调用动态链接库中的函数时,它才发挥作用。

    一、静态库与动态库

    1、静态库

    函数和数据被编译进一个二进制文件(.LIB),编译时,会将其组合起来创建最终

    的可执行文件(.exe文件),当发布产品时,只需要发布这个可执行文件,并不需要发

    布被使用的静态库。

    2、动态库

    在使用动态库的时候,往往提供两个文件:一个引入库(.Lib)文件和一个DLL(.dll)

    文件。

    引入库文件(.lib),包含该DLL导出的函数和变量的符号名,而.dll文件包含该Dll实际

    的函数和数据,

    在使用动态库的情况下,在编译链接可执行文件时(生成.exe文件),只需要链接该DLL

    的引入库文件(.Lib),直到可执行程序运行时(运行.exe),才去加载所需的DLL。

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

    Dumpbin  查看DLL中有哪些导出函数。

    进入到.dll所在目录,输入:dumpbin -exports  **.dll

    二、动态链接库的加载:隐式链接、显式加载

    为了让DLL导出一些函数,需要在每一个将要被导出的函数前面添加标识符:

    _declspce(dllexport),

    注:

    .Lib :引入库文件(保存的是.dll中导出的函数和变量的符号名)

    .exp:输入库文件

    .dll:存放是的导出和非导出的函数的源代码。

    名字改编:在编译链接时,C++会按照自己的规则篡改函数的名称

    1、隐式链接方式加载DLL(在别的项目中使用编写的.dll文件中的函数)

    为了编译成功:需要将.Lib文件加入到当前工程工作目录,可成功生成.exe

    为了运行成功:需要将.dll文件加入到当前工作目录,可使.exe成功运行。

    当用到动态链接库中的函数时,需要加载它们(搜索.dll并加载到内存中)

    搜索路径:1、程序的执行目录

              2、当前目录

      3、系统目录

      4、path环境变量中所列出的路径

    注:Depends工具

    查看一个可执行模块依赖的动态链接库。

    在引用以后,如果使用到dll中的函数时,声明时需要用到_declspec(dllimport) 声明为

    为外部函数,表示函数是从动态链接库中引入的,当然也可以用extern。

    不过与extern关键字相比,使用_declspce(dllimport),编译器可以生成运行效率更高的

    代码。

    如果像普通的#include “.h”一样使用dll库的函数,可以为.dll程序中添加一个“.h”文

    件内部放函数的声明,然后在.dll的 “cpp”文件中放函数的实现。

    然后在发布dll的同时将.Lib,.dll,.h文件一起提供。在需要使用到的地方#include “.h”

    文件就可以使用了。

    当然头文件的写法需要注意:

    如:DLL1.h

    #ifdef DLL1_API

    #else

    #define DLL1_API  _declspec(dllimport) //关键

    #endif

    DLL1_API int add(int a,int b);

    DLL1_API int substract(int a,int b);

    Dll1.cpp

    #define DLL1_API  _declspec(dllexport) //关键

    #include “DLL1.h”

    //实现代码

    三、从DLL中导出C++类

    如:在刚刚的DLL1.H文件中添加

    class DLL1_API Point

    {

    Public:

    Void output (int x,int y);

    };

    为了从动态链接库中导出一个类,只需要在class关键字和类名之前加入 导入/导出

    标识符,就可以导出整个类了。

    注:权限问题仍与原来的一样,public private protected.

    如果采用隐式链接方式加载DLL,一旦DLL更新了,如果要使用新,一定要将新的文件复

    制到你所在的工作目录。

    也可以只导出类中的某个函数,把class后的关键字去掉,在函数前面加入导入导出

    修饰符。

    注:这两种导出的访问方式是没有区别的,都是先构造该类的一个对象,然后利用该对象访问该类导出的成员函数。

    四、解决名字改编问题

    编译器在生成DLL时,会对导出的函数进行名字改编,(而不同的编译器使用的改编规

    则不一样)。如用C语言编写的程序访问调用C++编写的dll中的函数,就会出现问题。

    鉴于以上原因:希望动态链接库文件在编译时,导出函数的名称不要发生改变。

    为了实现:在定义导入/导出 函数时,加上extern “C”

    可使用

    extern  “C”//注意这个C是大写

    {

    //函数声明。

    }

    也可以在_declspec前加上extern “C”

    注:这种方法只能用于导出全局函数这种情况,不能用于导出类的成员函数。

    1、如果导出函数的调用约定发生了改变,那么即使使用了限定符,extern “C”

    ,该函数的名字仍会发生改编,这种情况下,可以通过一个称为模块定义文件

    (DEF)的方式来解决名字改编问题。

    在生成DLL工程的目录中,添加一个 .def文件(自创建),并在其中添加如下代码:

    LIBRARY dll_name

    EXPORTS

    函数名称1

    ....2=函数名称2

    ....3

    注:dll_name指定动态链接库的内部名称(必须与生成的动态链接库的名称匹配)

    EXPORTS下面指定的是:表面DLL导出的函数,以及为这些导出函数指定的符号名,

    常用的使用方法:
    1、如果名称一致,会以原名称导出

    2、如果前后名称不一致

    Entryname=internalname  //导出后的名称=导出前的名称。

    如:

    Add

    Sub

    更多方法百度EXPORT的使用方法。

  • 相关阅读:
    JNI和NDK的关系
    JNI和NDK的关系
    Android SDK结构分析
    设计模式:单例模式
    编程规范:占位符
    设计模式:工厂模式
    代码整洁之道----读书笔记
    个人编程规范
    装饰器函数
    异常处理
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3327534.html
Copyright © 2020-2023  润新知