dll文件详解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

DLL 文件详解
Part1
dll文件与exe文件的区别:
动态链接库(Dynamic Link Library,缩写为DLL)
是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。

动态链接库文件的扩展名一般是dll,也有可能是drv、sys和fon,它和可执行文件(exe)非常类似.
具体说:
DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用程序直接或间接调用。

动态链接是相对于静态链接而言的。

所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。

换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。

当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。

而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。

仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。

当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应的函数代码。

共有三种动态链接库的形式:Win32DLL,MFC常规DLL和MFC拓展DLL
1、Win32DLL使用的是Win32的API实现的,只能导出函数,能被各种应用程序调用,适用范围最广。

WIN32 DLL 是纯C++ API 写的,体积也比较小。

一般做MFC程序时,选用MFC DLL,MFC常规DLL没有显性DLLMAIN。

MFC DLL 使用了MFC 体积比较大,MFC DLL本身也分为两种,一种是常规DLL,一种是扩展DLL。

2.MFC常规DLL是适用MFC创建的,就像MFC程序跟Win32程序的关系一样,MFC常规DLL 和Win32DLL的关系也是如此。

它使用MFC的机制,只能导出标准C函数。

如此,它便可以被大部分Win32程序调用。

3.MFC拓展DLL也也使用的是MFC机制创建的,相比于MFC常规DLL,拓展DLL可以导出C++类和MFC派生类,如此扩大了DLL的接口范围。

此长彼消,MFC拓展DLL的适用范围较小,只能被MFC程序调用。

因为它导出的不只是函数,还有C++类和MFC派生类。

三者区别展开来说:
MFC DLL 和win32 DLL的差别就是一个使用MFC类库,一个不使用,如果你代码中用到的MFC,那么一定要创建MFC DLL,因为win32 DLL用不了MFC类。

MFC常规DLL在DLL内部可以用MFC类的,但是给外部的接口并不提供MFC类的支持,还是
提供Win32 DLL同样的接口,与Win32的差别在于,它的内部可以用MFC类。

扩展DLL可以有C++的接口,它可以导出C++类给客户端。

导出的函数可以使用C++/MFC数据类型做参数或返回值,导出一个类时客户端能创建类对象或者派生这个类。

同时,在DLL中也可以使用MFC。

MFC扩展DLL是通常实现从现有Microsoft基础类库类派生的可重用类的DLL。

MFC扩展DLL具有下列功能和要求:
1 客户端可执行文件必须是用定义的_AFXDLL编译的MFC应用程序。

2 扩展DLL也可由动态链接到MFC的规则DLL使用。

3 扩展DLL应该用定义的_AFXEXT编译。

这将强制同时定义_AFXDLL,并确保从MFC头文件中拉入正确的声明。

它也确保了在生成DLL时将AFX_EXT_CLASS定义为__declspec(dllexport),这在使用此宏声明扩展DLL中的类时是必要的。

4 扩展DLL不应实例化从CWinApp派生的类,而应依赖客户端应用程序(或DLL)提供此对象。

5 但扩展DLL应提供DllMain函数,并在那里执行任何必需的初始化。

扩展DLL是使用MFC动态链接库版本(也称作共享MFC版本)生成的。

只有用共享MFC 版本生成的MFC可执行文件
(应用程序或规则DLL)才能使用扩展DLL。

客户端应用程序和扩展DLL必须使用相同版本的MFCx0.dll。

使用扩展DLL,可以从MFC派生新的自定义类,然后将此“扩展”版本的MFC提供给调用DLL的应用程序。

具体执行时,主要是资源的管理:mfc扩展dll会把当前dll的句柄加入一个全局资源句柄列表。

而普通的dll则不会。

即使支持mfc也不会,这样你每次用mfc类创建资源的时候要多写几行代码。

但你用在mfc扩展dll用win32来访问资源也需要多写代码。

==============================================================
扩展DLL 可以导出类
扩展DLL服务器方的类定义:
class AFX_CLASS_EXPORT 到出类名: public 基类名
{
............
}
扩展DLL客户方的类声明头文件:
#pragma comment(lib,"lib文件名")
class AFX_CLASS_IMPORT 到出类名: public 基类名
{
............
}
==============================================================
常规DLL 可以导出标准C语言函数
常规DLL服务器方的函数定义:
//
头文件中函数声明
extern "C" __declspec(dllexport)
返回值函数名
(
形式参数声明
)

//源文件中函数实现
extern "C" __declspec(dllexport)
返回值函数名
(
形式参数声明
)

AFX_MANAGE_STATE ( AfxGetStaticModuleState() );// 第一条语句
..............

//
在def模块文件中声明函数序号
EXPORTS 导出函数名 @序号数字
常规DLL客户方的隐式函数声明头文件:
======================================================
另外,所有的动态链接库都有两种链接方式:隐式调用和显示调用。

隐式调用
编译程序时需要头文件、lib文件,运行时需要DLL文件,并且运行过程中DLL文件一直被占用。

显式调用
编译时什么都不需要,在需要使用DLL中的函数时,通过LoadLibrary()和FindProcAdress()这两个API调用。

只需要一个DLL文件即可,而且在需要使用的时候DLL才被占用,使用完毕即被解除占用。

DLL中有哪些函数可以通过Depends工具查询。

==================================================================
Part2
如何制作生成dll文件?
一.Win32动态链接库
1.制作的步骤:
(1)新建WIN32 Dynamic-link Library工程,工程名为MyDll,选择A simple DLL project 类型。

(2)MyDll.h的内容如下:
以下是引用片段:
extern "C" _declspec(dllexport) int sum(int a,int b);//本文所有的例子只有一个sum即加法函数。

(3)MyDll.cpp的内容如下:
以下是引用片段:
#include "stdafx.h"
#include "windows.h"
#include "MyDll.h"
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
extern "C" _declspec(dllexport)int sum(int a, int b)
{
return a+b;
}
(4)编译之后产生了MyDll.lib与MyDll.dll两个文件。

2.使用方法:
(1).隐式调用法:将MyDll.lib和MyDll.h拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:
以下是引用片段:
#include "MyDll.h"
#pragma comment(lib,"MyDll");
(2).显示调用法:将MyDll.lib和MyDll.h拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中包含头文件,如:
以下是引用片段:
#include "MyDll.h"
同时还需要在Project->Setting->Link->Object/library modules的框中增加MyDll.lib这个库。

二.MFC动态链接库
1.制作的步骤:
(1)新建MFC AppWizard(dll)工程,工程名为MFCDll,选择Regular DLL using shared MFC DLL类型。

(2)在生成的MFCDll.cpp文件后面增加下面几行:
以下是引用片段:
int sum(int a, int b)
{
return a+b;
}
(3)在生成的MFCDll.def文件后面增加如下:
以下是引用片段:
sum @1 ;表示第一个函数是sum
(4)编译后会产生两个文件MFCDll.lib,MFCDll.dll
2.使用方法
(1)隐式调用法:将MFCDll.lib拷贝到需要应用该DLL的工程的目录下,将MyDll.dll 拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:
//注意这里没有在MFCDll.h中声明函数,所以不能直接包含MFCDll.h来声明函数。

以下是引用片段:
#pragma comment(lib,"MFCDll");
int sum(int a, int b);
//当然如果你的DLL中有很多函数,那可以另外写个MFCDll.h,包含所有的函数声明,然后直接将头文件包含进去
(2)显示调用法:与Win32的调用方法一样,不需要#pragma comment(lib,"MFCDll");,但是需要在Project->Setting->Link->Object/library modules的框中增加MFCDll.lib这个库。

==========================================================
另一个例子:
具体在写DLL文件头文件中一般如此:
#ifdef DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR void alert();
}
这样使得在定义了DLL_EXPORT的环境下,头文件中,函数为导出;相反为导入。

于是,我们可以使用同一个头文件。

此时是在写DLL,还是在使用DLL,只需要通过这个开关
来告诉编译器就可以了。

实现cpp中一般这么写:
#include "stdafx.h"
#define DLL_EXPORT
#include "MyHead.h"
extern "C"
{
DECLDIR void alert()
{
MessageBoxA(NULL, "Hello,World!", 0, 0);
}
}
在引用头文件前定义DLL_EXPORT,告诉编译器此时这些函数需要导出。

隐式调用
#include "stdafx.h"
#include "MyHead.h"
#pragma comment(lib,"MyTestDLL.lib")
int _tmain(int argc, _TCHAR* argv[])
{
alert(); // 直接调用
return 0;
}
由于我们没有定义DLL_EXPORT,那么头文件中的函数就会被从DLL中导入。

显式调用
#include "stdafx.h"
#include <windows.h>
typedef void (*alert)();
int _tmain(int argc, _TCHAR* argv[])
{
alert func = NULL;
HINSTANCE h = LoadLibraryA("MyTestDLL.dll");
if (h)
func = (alert)GetProcAddress(h, "alert");
if (NULL != func)
func();
FreeLibrary(h);
return 0;
}
首先定义函数指针类型,然后实例化一个该类型的函数。

最后调用即可。

相关文档
最新文档