动态链接库DLL

来源:互联网 发布:保罗加索尔总决赛数据 编辑:程序博客网 时间:2024/06/04 18:32

动态链接库

1.静态库和动态库

        静态库:函数和数据被编译进一个二进制文件(通常使用扩展名.LIB)。在使用静态库的情况下,在编译链接可执行文件时,连接器从库中复制这些函数和数据并把他们和应用程序的其他模块组合起来创建最终的可执行文件(.EXE文件)。当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。

动态库:在使用动态库时,往往提供两个文件:一个引入库(.lib)文件和一个DLL(.dll)文件。虽然引入库的后缀名也是“lib”,但是动态库文件和静态库文件有着本质上的区别,对一个DLL来说,其引入库文件(.lib)包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据。在使用动态库的情况下,在编译链接可执行文件时,只需要链接该DLL的引入库文件,该DLL中的函数代码和数据并不复制到可执行文件中,直到可执行文程序运行时,采取加载所需的DLL,将该DLL映射到进程的地址空间,然后访问DLL中导出的函数。这时,在发布产品时,除了发布可执行文件以外,同时还要发布该程序将要调用的动态链接库。

 

动态链接库加载方式有以下两种:

隐式链接

显式加载

 

2.Win32DLL的创建和使用

新建一个Win32 Dynamic-Link Library项目,然后加入源文件Dll1.cpp,添加代码如下:

int add(int a, int b)

{

          returna+b;

}

int subtract(int a, int b)

{

          returna-b;

}

Build后将看到生成的Dll1.dll文件。

2.1Dumpbin命令

应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数。为了查看一个DLL中有哪些函数,可以利用命令行工具:Dumpbin实现。

点击工具->visual studio命令提示,在弹出的命令行窗口中直接输入DUMPBIN即可查看该命令的使用方法。可以使用/EXPORTS选项来运行Dumpbin命令来查看一个DLL提供的导出函数。如下

进入DLL1.dll所在文件夹,输入dumpbin -exports dll1.dll


即可看到一些信息,但我们没有看到任何与函数有关的信息,说明Dll.dll没有导出函数。

2.2从DLL中导出函数

为了让DLL导出一些函数,需要在每一个将要被导出的函数面前添加标识符:_declspec(dllexport)。修改上述代码如下;

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

{

          returna+b;

}

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

{

         returna-b;

}

可以看到这是生成了两个新文件DLL.lib和DLL.exp,其中DLL.lib文件就是前面提到的引入文件。在此运行dumpbin查看DLL.dll导出函数的信息,结果如下:


可以看到这时有add和subtract两个导出函数的信息,导出函数名?add@@YAHH@Z是按编译器的名字改编规则命名,下面会讨论这个问题。导出类和导出类中的函数也是相同的方式。

 

3.隐式链接方式加载DLL

3.1利用extern声明外部函数

新建一个机遇对话框的MFC应用程序,工程名趣味DllTest,并在主对话框上防止两个按钮。

然后添加如下代码:

extern int add(int a, int b);extern int subtract(int a, int b);void CDllTestDlg::OnBnClickedBtnAdd(){         //TODO: Add your control notification handler code here         CStringstr;         str.Format("5+3=%d",add(5+3));         MessageBox(str);} void CDllTestDlg::OnBnClickedBtnSubtract(){         //TODO: Add your control notification handler code here         CStringstr;         str.Format("5-3=%d",subtract(5,3));         MessageBox(str);}

这是编译将在连接时出错,因为链接器不知道两个函数在什么地方实现。然后将DLL.dll文件复制到DLLTest程序所在目录下,并在工程属性linker的COMMOND LINE中添加DLL.lib。经过编译后产生DllTest.exe文件。也就是说在程序链接时只需包含该动态链接库提供的输入库文本就可以了。

在DllTest.exe文件夹下输入

Dumpbin –imports lltest.exe

可看到结果如下


这说明DllTest程序需要调用DLL.dll中的add和subtract函数。

运行DLLTest.exe时,将会发生错误,提示找不到DLL.dll。当应用程序运行时,系统将为它分配一个4GB的地址空间,然后加载模块会分析该应用程序的输入信息,从中找到该程序将要访问的动态链接库信息,然后在用户机器上搜索这些动态链接库,进而夹在他们。

搜索的目录一次是:

1>.程序的执行目录

2>当前目录

3>系统目录

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

这里我们将DLL.dll防止在DllTest工程所在目录下,然后在此运行DLLtest.exe,结果如下:


3.2利用_declpes(dllimport)声明外部函数

标识符_declspec(dllimport)可以表明函数是从动态链接库中引入的。改动代码如下:

//extern int add(int a, int b);

//extern int subtract(int a, int b);

_declspec(dllimport) int add(int a, int b);

_declspec(dllimport) int subtract(int a, intb);

 

4.完善Win32 DLL例子

为方便DLL使用,通常在编写动态链接库时,都会提供一个头文件,在此头文件中提供DLL导出函数原型的声明,以及函数的有关注释文档。

接下来我们为DLL添加一个头文件DLL.h,并在其中添加如下代码

_declspec(dllimport) int add(int a, int b);

_declspec(dllimport) int subtract(int a,int b);

接下俩将DLLTestDlg.cpp中两个函数的声明注释掉,添加该头文件如下

#include "..\..\DLL\DLL\Dll1.h"

编译并运行程序,结果一样。

通过上述方法,在发布DLL.dll动态链接库的同时,可以将DLL.h这个头文件一起提供给使用者。

 

5.解决名字改编问题

1> C与C++之间加入 extern “C”

2>添加.def模块文件

 

6.显式加载方式加载DLL

HINSTANCE LoadLibrary(

LPCTSTR lpLibFileName);

 

FARPROC GetProcAddress(

HMODULE hModule,

LPCWSTR lpProcName);

 

6.调用约定

_stdcall

当DLL中导出函数采用的是标准调用约定时,访问该DLL的客户端程序也应该采用该约定类型访问相应的导出函数。

 

7.其他

DLL的入口函数是DllMain

如果采用动态加载方式使用DLL时,在需要访问时,调用LoadLibary函数加载该DLL;当不需要访问该DLL时,调用FreeLibrary函数释放对该DLL的引用。



==参考 VC++深入详解、

==转载请注明出处,谢谢!

0 0
原创粉丝点击