写在前面
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 <windows.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接口函数了。