动态链接库是编绎好的二进制文件与exe文件类似,但它不能单独运行。它是一个独立的模块,也包含了代码、数据或资源,能被其它程序共享。多个程序调用动态链接库里的同一个函数时,理论上该函数在内存中只存在一份拷贝。

静态链接库编绎器在编绎时会将函数和过程都编绎到可执行文件中,这样会造成可执行文件很大。多个程序调用静态链接库时,每个程序都拥有该库里函数的拷贝,若这些程序同时运行则内存中会拥有该库中函数的多份拷贝。

动态链接库的好处:

1 有利于程序的模块化。

2 共享代码、数据、资源。

3 程序在运行时调入代码运行,而不是将其编绎到可执行文件中,节省了内存。动态链接库调用方式:

1 隐式链接,即使不调用库里面的函数,启动时也会加载库文件。需要把产生动态链接库时产生的.lib文件加入到应用程序工程中,该文件包含了每一个dll导出函数的符号名和可选的标识号,但是并不含有实际的代码。lib文件作为dll的替代文件被编译到应用程序项目中。

2 显式链接,是指在应用程序中用LoadLibraryMFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,再用GetProcAddress()获取想要引入的函数。用完时调用FreeLibrary对动态库进行卸载。频繁的调用会牺牲一部分时间。

 

以下用一个例子来说明这两种调用。

1 VC6.0下新建一个WIN32 Dynamic Library工程,工程名为mydll1,然后在这个工程中建立mydll.h , mydll.cpp这两个文件,文件的类容分别为:

mydll.h

#ifndef MYDLL_H

#define MYDLL_H

#ifdef API_DLL

#else

#define API_DLL _declspec(dllimport) //_declspec(dllimport)声明函数是导入函数,表示此//函数是从外部导入进来了函数,一般在调用dll的程序中这样声明。此处这个头文件会被//调用程序所使用。

#endif

API_DLL int add(int a,int b);

API_DLL int sub(int a,int b);

#endif

 

mydll.cpp

#include “mydll.h”

#define API_DLL _declspec(dllexport) //_declspec(dllexport)声明函数是导出函数,表示此//函数是导出给外部程序使用的。

int add(int a,int b)

{

         return a+b;

}

int sub(int a,int b)

{

         return a-b;

}

编绎、链接后,在工程文件下可以发现mydll.dll, mydll.lib这两个文件。这两个文件在以后的隐式链接中会用到。

 

2 VC6.0下再建一个WIN32 Dynamic Library工程,工程名为dll2,然后在这个工程中建立dll2.cpp这两个文件,文件的类容为:

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

{

         return a>b?a:b;

}

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

{

         return a<b?a:b;

}

编绎链接后,可以在工程文件下发现dll2.dll这个文件。这个文件在接下来的工程中会被用来显示链接。

3 VC6.0下再建一个WIN32 Consol Application工程,工程名为calldll然后在这个工程中建立calldll.cpp文件,文件的类容为:

calldll.cpp

#include <stdio.h>

#include “windows.h”

#include “mydll.h”

#pragma comment(lib,”mydll.lib”)//这行可以不要,如果不要这行的话需要在//Project---setting---link---object/library中加入mydll.lib

 

void main()

{

    //下面这8行是显示加载dll2.dll中的函数

         HINSTANCE hint;

         hint=LoadLibrary(“dll2.dll”);              //加载dll2.dll

         typedef int (*FUN)(int a,int b);            // 自定义函数指针

         FUN MAX=(FUN)GetProcAddress(hint,“max”);// 获取dll2.dll中的max函数句柄

         FUN MIN=(FUN)GetProcAddress(hint,“min”);// 获取dll2.dll中的min函数句柄

         printf(“%d \n”,MAX(1,2));

         printf(“%d \n”,MIN(1,2));

         FreeLibrary(hint);       //释放动态链接库dll2.dll

    //下面两行是调用mydll中的addsub函数。

         printf(“%d \n”,add(1,2));

         printf(“%d \n”,sub(1,2));

        

}

在完成了以上三步后,还不能通过编绎第三个工程,要想通过编绎,先把第一个工程也就是mydll这个工程中的mydll.dll,mydll.lib,mydll.h这三个文件拷贝到calldll工程文件中也就是与calldll中的.cpp文件在同一目录,然后把dll2这个文件中的dll2.dll也拷到calldll工程中,这下编绎、链接calldll这个工程,如果没有错误的话。那么就可以直接运行了,运行过后会看到所期望的结果。

这里因为dll2.dll是显示调用的所以只拷贝dll2.dll这个文件到calldll这个工程中就行了。

mydll.dll是隐式调用的所以需要将mydll.lib也放到工程中去。

 

编写此文参考了以下这个地址的内容。

http://blog.csdn.net/zieckey/article/details/1418653