• 22.windows库程序(二)


    1.动态库程序

      (1)动态库特点

         运行时独立存在

         不会链接到执行程序

         使用时加载(使动态库程序运行)

      (2)与静态库的比较

         由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码的体积会增大。

         动态库的代码只需要存在一份,其他程序通过函数地址使用,代码体积小。

         静态库发生变化后,新的代码需重新嵌入到执行程序中。

         动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用的程序不需要重新链接。

    2.创建动态库

      (1)建立项目

      (2)添加库程序

      (3)库程序导出(偏移地址)- 提供给使用者库中的函数信息

    3.动态库使用

      (1)隐式链接(使动态库程序运行起来的过程不需要程序员负责)

      (2)显式链接(使动态库程序运行起来的过程需要程序员自己负责)

    4.动态库函数

      (1)实现动态库函数

      (2)库函数导出

         a.声明导出

           使用_declspec(dllexport)导出函数

           注意:动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同。

         b.模块定义文件 .def

           例如:LIBRARY DLLFunc   //库

              EXPORTS               //库导出表

              DLL_Mul   @1         //导出的函数

    5.库函数的使用

      (1)隐式链接

         头文件和函数原型

           可以在函数原型的定义前,增加_declspec(dllimport),例如_declspec(dllimport)int DLL_Add( .. );

           如果库函数使用C格式导出,需要在函数定义前增加extern "C"

         b.导入动态库的LIB文件

         c.在程序中使用函数

         d.隐式链接的情况,DLL可以存放的路径:

           与可执行文件在同一目录下

           当前工作目录

           Windows目录

           Windows/System32目录

           Windows/System

           环境变量PATH指定目录

           注意:高版本VC的配置文件

      (2)显示链接

         a.定义函数指针类型

         b.加载动态库(使动态库程序运行)

           HMODULE LoadLibrary( LPCTSTR lpFileName);  //动态库文件名或全路径

           返回DLL实例句柄(HINSTANCE)

         c.获取函数地址

           FARPROC GetProcAddress( HMODULE  hModule,        //DLL句柄

                                                               LPCSTR     lpProcName);  //函数名称

           成功返回函数地址

         d.使用函数

         e.卸载动态库

           BOOL FreeLibrary( HMODULE hModule);  //DLL实例句柄

      相关代码:

      (1)动态库代码 

    //导出
    _declspec(dllexport) int CPPdll_add(int a, int b)
    {
        return a + b;
    }
    
    _declspec(dllexport) int CPPdll_sub(int a, int b)
    {
        return a - b;
    }

      (2)使用动态库(函数要换名)

    #include "windows.h"
    #include <iostream>
    
    
    //1.定义函数指针类型
    typedef int(*DLL_FUNC)(int, int);
    
    
    int main()
    {
        //2.加载动态库
        HINSTANCE hDll = LoadLibrary("CPPdll.dll");
        std::cout << "hDll:" << hDll << std::endl;
    
        //3.获取函数地址
        DLL_FUNC myAdd = (DLL_FUNC)GetProcAddress(hDll, "?CPPdll_add@@YAHHH@Z");
        std::cout << "myAdd:" << std::hex << myAdd << std::endl;
    
        //4.使用函数
        int sum = myAdd(5, 6);
        std::cout << "sum=" << std::dec << sum << std::endl;
    
        DLL_FUNC mySub = (DLL_FUNC)GetProcAddress(hDll, "?CPPdll_sub@@YAHHH@Z");
        std::cout << "mySub:" << std::hex << mySub << std::endl;
        int sub = mySub(5, 6);
        std::cout << "sub=" << std::dec << sub << std::endl;
    
        //5.下载动态库
        FreeLibrary(hDll);
    
        return 0;
    }

      运行结果:

      

    总结:

      1.制作动态库

        (1)声明导出:_declspec(dllexport),将函数的偏移地址导到了dll的文件头中。

           如果是C++编译器,dll文件中记录的是换名之后的函数名对应的偏移地址。

           lib文件中记录的仅仅是换名之后的函数名对应的编号。

        (2)模块定义文件导出:将函数的偏移地址导到了dll的文件头中。

           即便是C++编译器,dll文件头中记录的是未换名的函数名对应的偏移地址。

           lib文件中记录的仅仅是未换名之后的函数名对应的编号。

      2.使用动态库

        (1)隐式链接

           操作系统的加载器负责使动态库执行(拿到dll首地址)。

           链接器负责到lib文件中拿函数的编号,程序执行起来后,操作系统加载器拿着编号到dll文件头中查询函数的偏移地址。

        (2)显示链接

           调用LoadLibrary使动态库执行(拿到dll首地址)。

           调用GetProcAddress函数,通过函数的名称到dll文件头中查询函数的偏移地址。例如:GetProcAddress( hDll, "CPPDll_add")

      3.两种链接方式对比

        (1)在库函数定义不变的情况下

           隐式链接:由于库函数地址是在程序编译链接时设置的,所以当动态库变化后,使用程序需要重新编译链接。

           显示链接:由于库函数地址是在程序执行时动态的从库中查询,所以变化后不需要重新编译链接。

        (2)动态库加载时间

           隐式链接:动态库是在程序运行时被加载的,当dll不存在时,程序无法启动。

           显示链接:动态库只在使用LoadLibrary函数时,才会被加载。

  • 相关阅读:
    x86 hook跳转内存地址转换计算框架
    win10180317134配合VS2017搭建WDK驱动开发环境
    C/C++字节特征码转换自动格式化文本工具算法源码
    jar包直接拷贝到WEBINF/lib下和以userLibrary引入的区别
    java.io.IOException: Cannot rename original file to %TOMCAT_HOME%\conf\tomcatusers.xml.old
    Tomcat5 和 Tomcat6 类加载器架构
    Tomcat version * only supports J2EE * Web modules
    tomcat启动时报错:org.apache.catalina.core.AprLifecycleListener init
    tomcat 不能正常启动,双击 startup.bat 一闪而过
    java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
  • 原文地址:https://www.cnblogs.com/csqtech/p/5657457.html
Copyright © 2020-2023  润新知