动态链接库小结

、链接库概述

      使用动态链接库可以实现软件设计的模块化,动态链接库是在运行时才进行连接并能够共享的函数库,可以将不同功能的模块封装到不同的链接库中,功能相同或相似的模块封装到相同的链接库中。链接库是一个以二进制方式存储数据的磁盘文件,它本身不能运行,需要其他的应用程序执行时加载或编译前进行引用。DLL就是完成一定功能的模块,既可以包含数据、函数,也可以包含类。DLL中包含两种对象:

1)导出对象:如导出数据、导出函数和导出类,此种对象可以被其他可执行模块调用。虽然DLL可以导出数据,但是通常DLL中的数据都是内部数据,仅供内部函数使用,不建议从DLL中导出数据。

2)内部对象:如内部数据、内部函数和内部类,此种对象只能在DLL内部由内部使用。

     DLL动态链接库和EXE可执行文件类似,都是可执行程序模块,但是也存在很多不同之处。对于用户来说,最大的差别在于DLL不是可以直接执行的程序。从系统的角度来看,他们之间存在两个基本的区别。一是应用程序可以在系统中同步运行多个实例,而DLL只能有一个实例。而是应用程序可以管理诸如堆栈、全局内存、文件句柄和消息队列等资源,而DLL不能管理这些资源。

链接库可以分为静态链接库和动态链接库两种。

1)静态链接库:它经常是一些相对小的,比较稳定的函数库,例如stdlib.lib。静态链接库通常是几组与应用程序相链接的可重用的函数,静态链接库是应用程序的一部分,如果静态链接库中的内容更新了,那么应用程序就要和新的静态链接库重新链接。

2)动态链接库:其可以在需要的时候动态加载到内存中,而且动态链接库在内存中只有一个实例,如果一个应用程序调用了DLL,其他应用程序也调用了该DLL,那么第2个程序只是将DLL在内存中的地址映射到自己的进程地址空间中;系统有一个计数器,记录有多少个应用程序在使用DLL。如果计数器为0,则将DLL从内存中卸载。在16为windows系统中DLL是被加载到共享地址空间的,而在windows200下,DLL被映射到应用程序自己的进程地址空间。

      静态链接库和动态链接库的一个主要区别在于静态链接库中不能再包含其他的动态链接库和静态链接库,而在动态链接库中还可以再包含其他的动态或静态链接库。

2、动态链接库的创建及调用

1)创建动态链接库

     Visual C++支持三种DLL:Non-MFC DLL(非MFC动态链接库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。非MFC动态链接库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接库版本创建,它只能被用MFC类库编写的应用程序所调用。

  • File->New->Project...,在出现的对话框中选择Win32标签下的Win32 Project,输入解决方案名和工程名。
  • 选择应用程序类型为DLL,附加选项中选择空工程,点击完成。
  • Configuration Properties->General,将Configuration Type中设置为Dynamic Library (.dll),将Use of MFC中设置为Use Stand Windows Libraries
  • Configuration Properties->C/C++->Code Generation,在Runtime Library中指定运行时库为Multi-threaded Debug DLL (/MDd)
  • 添加库文件程序源代码。
    1. //MathFuncsDll.h  
    2. namespace MathFuncs  
    3. {  
    4.     class MyMathFuncs  
    5.     {  
    6.     public:  
    7.         static __declspec(dllexport) double Add(double a, double b);  
    8.         static __declspec(dllexport) double Subtract(double a, double b);  
    9.         static __declspec(dllexport) double Multiply(double a, double b);  
    10.         static __declspec(dllexport) double Divide(double a, double b);  
    11.     };  
    12.   
    13. #include "MathFuncsDll.h"  
    14. #include <stdexcept>  
    15. namespace MathFuncs  
    16. {  
    17.     double MyMathFuncs::Add(double a, double b)  
    18.     {  
    19.         return a+b;  
    20.     }  
    21.     double MyMathFuncs::Subtract(double a, double b)  
    22.     {  
    23.         return a-b;  
    24.     }  
    25.     double MyMathFuncs::Multiply(double a, double b)  
    26.     {  
    27.         return a*b;  
    28.     }  
    29.     double MyMathFuncs::Divide(double a, double b)  
    30.     {  
    31.         if(b == 0)  
    32.         {  
    33.             throw std::invalid_argument::invalid_argument("b cannot be zero!");  
    34.         }  
    35.         return a/b;  
    36.     }  
    37. }  
    38. }  
  • 将上述代码加入到工程中,Build->Build Solution,在输出目录中即可生成需要的动态库文件了。

至此,所需要的库文件便编译好了。在工程目录下的debug目录下生成了两个文件.lib和.dll,其中.lib是导出函数源代码的实现,而.dll就是需要的动态链接库文件。

2)静态链接库的调用及动态链接库的隐式调用

#include "xxx.h"     //包含链接库的头文件

#pragma comment(lib, "xxx")  //隐式调用库文件.lib

上述代码就是隐式链接的方法。其中语句#pragma comment(lib,"xxx")可以通过工程设置对话框来设置代替。

  • properties->Configuration Properties->Debugging,在Enviroment中设置动态库.dll文件的路径名。其格式为:PATH=<.dll文件名>。
  • Configuration Properties->C/C++->General,在Additional Include Directories中添加snmp++类库头文件的路径,多个路径之间用分号隔开。
  • Configuration Properties->C/C++->Code Generation,在Runtime Library中指定运行时库为Muti-thread Debug Dll (/MDd)
  • Configuration Properties->Linker->General->Additional Library Directories中指定.lib库文件的所在目录,在Configuration Properties->Linker->Input中输入xxx.lib.
  • 添加程序源代码
    1. #include "stdafx.h"  
    2. #include <iostream>  
    3. #include "../MathFuncsDll/MathFuncsDll.h"  
    4. using namespace std;  
    5. #pragma comment(lib,"..//Debug//MathFuncsDll.lib")  
    6. int main()  
    7. {  
    8.     double a = 7.4;  
    9.     int b = 99;  
    10.   
    11.     cout<<"a + b = "<<MathFuncs::MyMathFuncs::Add(a,b)<<endl;  
    12.     cout<<"a - b = "<<MathFuncs::MyMathFuncs::Subtract(a,b)<<endl;  
    13.     cout<<"a * b = "<<MathFuncs::MyMathFuncs::Multiply(a,b)<<endl;  
    14.     cout<<"a / b = "<<MathFuncs::MyMathFuncs::Divide(a,b)<<endl;  
    15.   
    16.     return 0;  
    17. }  
  • Build->Build Solution,在输出目录中即可生成可执行文件xxx.exe文件。

至此,运行xxx.exe文件即可看到程序的运行结果。对上述源代码进行分析可以看出,在该动态库中导出的是函数而不是类。对于函数的导出,也可以用显式调用方式。

3)动态链接库的显式调用

显式调用的动态加载主要是通过LoadLibrary和GetProcAddress两个函数来实现的。

  • LoadLibrary()用于装载模块,动态链接库和可执行程序都是模块,如果函数执行成功,返回模块句柄,这个句柄会在GetProcAddress中使用。其语法格式如下:

      HINSTANCE LoadLibrary(LPCTSTR lpLibFileName);

      其中:lpLibFileName是要装载的动态链接库和可执行程序的文件名,可以是相对路径也可以是绝对路径。

  • GetProcAddress()用于获得模块的函数地址。如果函数执行成功,返回模块中具体函数的指针。其语法为:

      GetProcAddress(HMODULE hModule, LPCSTR lpProcName)

      其中:hModule是加载到内存中的模块的句柄,主要指LoadLibrary的返回值。

            lpPorcName是函数的名称

  在显式调用中,首先要定义一个指向导出函数的函数指针,然后调用LoadLibrary和GetProcAddress,获得函数指针,即可像使用本地函数一样使用导出函数。在此不再赘述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值