动态链接库是编绎好的二进制文件与exe文件类似,但它不能单独运行。它是一个独立的模块,也包含了代码、数据或资源,能被其它程序共享。多个程序调用动态链接库里的同一个函数时,理论上该函数在内存中只存在一份拷贝。
静态链接库编绎器在编绎时会将函数和过程都编绎到可执行文件中,这样会造成可执行文件很大。多个程序调用静态链接库时,每个程序都拥有该库里函数的拷贝,若这些程序同时运行则内存中会拥有该库中函数的多份拷贝。
动态链接库的好处:
1 有利于程序的模块化。
2 共享代码、数据、资源。
3 程序在运行时调入代码运行,而不是将其编绎到可执行文件中,节省了内存。动态链接库调用方式:
1 隐式链接,即使不调用库里面的函数,启动时也会加载库文件。需要把产生动态链接库时产生的.lib文件加入到应用程序工程中,该文件包含了每一个dll导出函数的符号名和可选的标识号,但是并不含有实际的代码。lib文件作为dll的替代文件被编译到应用程序项目中。
2 显式链接,是指在应用程序中用LoadLibrary或MFC提供的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中的add和sub函数。
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