Dll是Dynamic Linkable Library的簡稱,是Windows系統下一種關鍵的程序運行方式。形式上,Dll是保存一些全局數據、函數、類等資源的文件,後綴名可以為.dll,.fon,.drv,.sys,.exe等等。
它自己不能運行,需要由應用程序來調用,也正因為這樣,才促成了它的跨語言使用的特定:可以用某種語言編寫一個Dll,然後用另一種語言調用,當然,這需要語言的支持。這種將數據和應用、函數庫和應用程序的分離,使Dll在Win32平台上大顯身手,一舉成為Windows系統的主要調用方式,實際上,Windows中很多主要的函數都包括在Dll中,比如kernel.dll包含了內存管理、進程管理等函數,user32.dll包含了圖形界面的相關函數,而gdi32.dll則包含了底層的畫圖及文本顯示函數。
另外,Dll在內存中有唯一的映射,因此
下面首先通過一個簡單實例來看看Dll是如何工作的。
入門實例
用VC程序寫一個dll,再以另一個VC程序對其調用:
首先,建立一個Win32 Dynamic-Link Library類型的工程hellodll,包含如下兩個文件:
1) hellodll.h
#ifndef DLLEXPORT
#define DLLEXPORT extern "C" _declspec(dllimport)
#endif
DLLEXPORT int _stdcall add(int a,int b);
2) hellodll.cpp
#include "hellodll.h"
#include <stdio.h>
int _stdcall add(int a,int b)
{
return a+b;
}
在VC中進行build,得到Debug下的hellodll.dll和hellodll.lib。
建立另外一個普通工程hellodll_app,主程序如下:
3) hellodll_app.cpp
#include <stdio.h>
#include <iOStream>
using namespace std;
typedef int (* AddFunc)(int a,int b); // 1
int main(int argc,char *argv[])
{
int a=1,b=2,c;
AddFunc add;
HINSTANCE hInstLib = LoadLibrary("D:\\Program Files\\Microsoft Visual Studio\\MyProjects\\hellodll\\Debug\\hellodll.dll");
if (hInstLib == NULL)
{
cout<<"Dll failed to load." <<endl;
FreeLibrary(hInstLib);
system("pause");
return 1;
}
add = (AddFunc)GetProcAddress(hInstLib,"add"); // 2
if(!add)
{
FreeLibrary(hInstLib);
cout << "Dll Function add() got failed." << endl;
return 1;
}
c = add(a,b);
FreeLibrary(hInstLib);
printf("add(%d,%d):%d\n",a,b,c);
return 0;
}
4)運行
一開始,運行提示"Dll Function add() got failed.",查看hellodll.lib,發現輸出的API名字已經變成了_add@8,將注釋//2處:
add = (AddFunc)GetProcAddress(hInstLib," add");
修改為:
add = (AddFunc)GetProcAddress(hInstLib,"_add@8");
故障解除。
又運行,出現錯誤:The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
將注釋//1處:
typedef int (* AddFunc)(int a,int b);
修改為:
typedef int (__stdcall * AddFunc)(int a,int b);
至此,運行正常。
那麼,在第一個錯誤中,怎麼能直接調用add函數呢?
答案是:去掉1) hellodll.h,添加 5) hellodll.def,如下:
5)hellodll.def
LIBRARY hellodll
EXPORTS
add
當然,在hellodll.cpp中也要刪除對hellodll.h的#include。
這樣,編譯鏈接生成hellodll.dll,那麼在hellodll-app.cpp的注釋//2處就可以使用
add = (AddFunc)GetProcAddress(hInstLib,"add");
得到dll接口函數了。