• VC 静态库与动态库(三)动态库创建与使用_隐式链接


    动态库分为二种,一种隐式链接,另一种显示调用。不论哪种动态库,本质都是运行时动态加载

    隐式链接:程序运行时,由编译系统自动加载动态库,然后根据程序的引入表进行重定位,当程序退出时自动卸载动态库

    显示调用:程序运行时,在需要使用动态库时手动使用LoadLibrary进行加载,当不需要动态库时使用FreeLibrary进行卸载

    动态库创建:

    1.新建项目,创建项目和解决方案

    DynamicLibrary  这是动态库项目

    G:C++LearnLibrary  Library文件夹用于存放库相关文件,包含静态库与动态库工程和解决方案

    DynamicLibraryDemo  动态库解决方案名称

     2.点击下一步,出现如下界面

    选择DLL,选择导出符号,如果需要使用MFC就勾选上,最后点击完成

     3.然后VS左边解决方案管理器会显示相关文件

    这就是个最简单的动态库,编译生成下

    4.文件夹生成了相关文件

    解决方案目录:

    解决方案目录下,项目文件夹DynamicLibrary,Debug解决方案调试目录下面就存放了编译生成的 输入库(.lib)和动态链接库(.dll)

     

    回顾下静态库生成,一对比就会发现静态库生成时没有.dll文件

    5. 动态库比静态库生成的文件稍显复杂些,这里稍微介绍下

    首先看下DynamicLibrary.h,这里由于在第二步时勾选了导出符号,所以VS会默认产生一个与工程

    同名的.h文件包含示例代码,导出了相关类和函数帮助我们了解动态库使用

    注意:如果没有勾选导出符号,是不会生成DynamicLibrary.h文件的,需要自己进行创建.h进行导出

     1 // 下列 ifdef 块是创建使从 DLL 导出更简单的
     2 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 DYNAMICLIBRARY_EXPORTS
     3 // 符号编译的。在使用此 DLL 的
     4 // 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
     5 // DYNAMICLIBRARY_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
     6 // 符号视为是被导出的。
     7 #ifdef DYNAMICLIBRARY_EXPORTS
     8 #define DYNAMICLIBRARY_API __declspec(dllexport)
     9 #else
    10 #define DYNAMICLIBRARY_API __declspec(dllimport)
    11 #endif
    12 
    13 // 此类是从 DynamicLibrary.dll 导出的
    14 class DYNAMICLIBRARY_API CDynamicLibrary {
    15 public:
    16     CDynamicLibrary(void);
    17     // TODO: 在此添加您的方法。
    18 };
    19 
    20 extern DYNAMICLIBRARY_API int nDynamicLibrary;
    21 
    22 DYNAMICLIBRARY_API int fnDynamicLibrary(void);

    7-11行的宏定义在不同工程中起到不同的作用。

    在当前动态库工程中由于定义了DYNAMICLIBRARY_EXPORTS宏, 所以这个宏表示的是导出

    而在外部程序,虽然使用动态库包含了这个头文件,但是没有定义这个宏,所以这个宏表示的是导入

    13-22行用到的宏也是一样的作用,在当前动态库工程中代表的是导出,在外部程序中代表的导入

    可能有人会发现工程下文件并没有定义这个宏,为什么会说这个宏己经被定义呢?

    答案就是这个宏在VS的预处理器定义了,创建动态库项目时,VS会自动帮你在预处理器中添加一个与工程项目

    相同,全部大写后面加上_EXPORTS的一个宏

    当然也可以在头文件中修改宏的名字,但是相应的预处理器定义里也得保持一致

    DynamicLibrary.cpp文件

    // DynamicLibrary.cpp : 定义 DLL 应用程序的导出函数。
    //

    
    

    #include "stdafx.h"
    #include "DynamicLibrary.h"

    
    


    // 这是导出变量的一个示例
    DYNAMICLIBRARY_API int nDynamicLibrary=0;

    
    

    // 这是导出函数的一个示例。
    DYNAMICLIBRARY_API int fnDynamicLibrary(void)
    {
    return 42;
    }

    
    

    // 这是已导出类的构造函数。
    // 有关类定义的信息,请参阅 DynamicLibrary.h
    CDynamicLibrary::CDynamicLibrary()
    {
    return;
    }

     

     6. 给CDynamicLibrary类添加一个MathAdd方法,另外添加一个全局函数MathSub. 最后编译生成

    DynamicLibrary.h

    
    

    // 下列 ifdef 块是创建使从 DLL 导出更简单的
    // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 DYNAMICLIBRARY_EXPORTS
    // 符号编译的。在使用此 DLL 的
    // 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
    // DYNAMICLIBRARY_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
    // 符号视为是被导出的。
    #ifdef DYNAMICLIBRARY_EXPORTS
    #define DYNAMICLIBRARY_API __declspec(dllexport)
    #else
    #define DYNAMICLIBRARY_API __declspec(dllimport)
    #endif

    
    

    // 此类是从 DynamicLibrary.dll 导出的
    class DYNAMICLIBRARY_API CDynamicLibrary {
    public:
    CDynamicLibrary(void);
    int MathAdd(int a,int b);//加法计算(类成员函数)
    };

    
    

    DYNAMICLIBRARY_API int MathSub(int a ,int b);//减法计算(全局函数)

    DynamicLibrary.cpp

    
    

    // DynamicLibrary.cpp : 定义 DLL 应用程序的导出函数。
    //

    
    

    #include "stdafx.h"
    #include "DynamicLibrary.h"

    
    


    //减法计算(全局函数)
    DYNAMICLIBRARY_API int MathSub(int a ,int b)
    {
    return a - b;
    }

    
    

    // 这是已导出类的构造函数。
    // 有关类定义的信息,请参阅 DynamicLibrary.h
    CDynamicLibrary::CDynamicLibrary()
    {
    return;
    }
    //加法计算(类成员函数)
    int CDynamicLibrary::MathAdd(int a,int b)
    {
    return a + b;
    }

    隐式链接项目创建:

    1.给解决方案添加一个新的控制台项目HideLink用于测试动态库,创建完成后设置为启动项目

    2.HideLink.cpp添加相关代码

    
    

    // HideLink.cpp : 定义控制台应用程序的入口点。
    //

    
    

    #include "stdafx.h"
    #include "../DynamicLibrary/DynamicLibrary.h" //动态库头文件

    
    

    #pragma comment(lib,"../Debug/DynamicLibrary.lib")//引入动态库.lib文件
    int _tmain(int argc, _TCHAR* argv[])
    {
    //使用动态库中CDynamicLibrary类,调用其中的MathAdd方法
    CDynamicLibrary dynamicLib;
    int nResult = dynamicLib.MathAdd(1,2);
    printf("1 + 2 = %d ",nResult);
    //调用动态库中的全局函数MathSub
    nResult = MathSub(5,1);
    printf("5 - 1 = %d ",nResult);
    getchar();
    return 0;
    }

    
    

    3. 编译运行HideLink, 查看相关信息

    控制台输出调试信息,下方的模快里不单有HideLink.exe以及系统dll,还多了个动态库DynamicLibrary.dll

    总结:虽然动态库的隐式链接方式和静态库调用代码差不多,但是二者内部实现是有明显差别的。

    静态库在链接阶段是直接打包到程序中,而动态库的隐式链接在链接阶段只是把用到的函数声明加入

    到引用表中,并不会把函数实现代码加入程序中,更不会把整个动态库打包进程序

  • 相关阅读:
    Android环境说明 与 屏幕尺寸问题
    关于修改Visual Studio 2010 Ultimate RC的密钥
    安装Office 2010是出现windows installer服务不能更新一个或多个受保护的windows文件 错误
    Sharepoint 2010和阿里通进行集成完成短信通知功能
    用visual studio 2010 打开winform程序 时 无法运行 的解决方案
    一次尴尬的招聘经历
    TFS里的MSB3021错误
    程序员是强者
    修改密码导致应用程序池无法启动
    远离客户开发陷阱(转)
  • 原文地址:https://www.cnblogs.com/fzxiaoyi/p/12055018.html
Copyright © 2020-2023  润新知