dll文件详解.docx
《dll文件详解.docx》由会员分享,可在线阅读,更多相关《dll文件详解.docx(10页珍藏版)》请在冰豆网上搜索。
dll文件详解
dll文件详解
DLL文件详解
Part1
dll文件与exe文件的区别:
动态链接库(DynamicLinkLibrary,缩写为DLL)
是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。
动态链接库文件的扩展名一般是dll,也有可能是drv、sys和fon,它和可执行文件(exe)非常类似.
具体说:
DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用程序直接或间接调用。
动态链接是相对于静态链接而言的。
所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。
换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。
当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。
它的内部可以用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服务器方的类定义:
classAFX_CLASS_EXPORT到出类名:
public基类名
{
............
}
扩展DLL客户方的类声明头文件:
#pragmacomment(lib,"lib文件名")
classAFX_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)新建WIN32Dynamic-linkLibrary工程,工程名为MyDll,选择AsimpleDLLproject类型。
(2)MyDll.h的内容如下:
以下是引用片段:
extern"C"_declspec(dllexport)intsum(inta,intb);//本文所有的例子只有一个sum即加法函数。
(3)MyDll.cpp的内容如下:
以下是引用片段:
#include"stdafx.h"
#include"windows.h"
#include"MyDll.h"
BOOLAPIENTRYDllMain(
HANDLEhModule,
DWORDul_reason_for_call,
LPVOIDlpReserved
)
{
returnTRUE;
}
extern"C"_declspec(dllexport)intsum(inta,intb)
{
returna+b;
}
(4)编译之后产生了MyDll.lib与MyDll.dll两个文件。
2.使用方法:
(1).隐式调用法:
将MyDll.lib和MyDll.h拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:
以下是引用片段:
#include"MyDll.h"
#pragmacomment(lib,"MyDll");
(2).显示调用法:
将MyDll.lib和MyDll.h拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中包含头文件,如:
以下是引用片段:
#include"MyDll.h"
同时还需要在Project->Setting->Link->Object/librarymodules的框中增加MyDll.lib这个库。
二.MFC动态链接库
1.制作的步骤:
(1)新建MFCAppWizard(dll)工程,工程名为MFCDll,选择RegularDLLusingsharedMFCDLL类型。
(2)在生成的MFCDll.cpp文件后面增加下面几行:
以下是引用片段:
intsum(inta,intb)
{
returna+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来声明函数。
以下是引用片段:
#pragmacomment(lib,"MFCDll");
intsum(inta,intb);
//当然如果你的DLL中有很多函数,那可以另外写个MFCDll.h,包含所有的函数声明,然后直接将头文件包含进去
(2)显示调用法:
与Win32的调用方法一样,不需要#pragmacomment(lib,"MFCDll");,但是需要在Project->Setting->Link->Object/librarymodules的框中增加MFCDll.lib这个库。
==========================================================
另一个例子:
具体在写DLL文件头文件中一般如此:
#ifdefDLL_EXPORT
#defineDECLDIR__declspec(dllexport)
#else
#defineDECLDIR__declspec(dllimport)
#endif
extern"C"
{
DECLDIRvoidalert();
}
这样使得在定义了DLL_EXPORT的环境下,头文件中,函数为导出;相反为导入。
于是,我们可以使用同一个头文件。
此时是在写DLL,还是在使用DLL,只需要通过这个开关来告诉编译器就可以了。
实现cpp中一般这么写:
#include"stdafx.h"
#defineDLL_EXPORT
#include"MyHead.h"
extern"C"
{
DECLDIRvoidalert()
{
MessageBoxA(NULL,"Hello,World!
",0,0);
}
}
在引用头文件前定义DLL_EXPORT,告诉编译器此时这些函数需要导出。
隐式调用
#include"stdafx.h"
#include"MyHead.h"
#pragmacomment(lib,"MyTestDLL.lib")
int_tmain(intargc,_TCHAR*argv[])
{
alert();//直接调用
return0;
}
由于我们没有定义DLL_EXPORT,那么头文件中的函数就会被从DLL中导入。
显式调用
#include"stdafx.h"
#include
typedefvoid(*alert)();
int_tmain(intargc,_TCHAR*argv[])
{
alertfunc=NULL;
HINSTANCEh=LoadLibraryA("MyTestDLL.dll");
if(h)
func=(alert)GetProcAddress(h,"alert");
if(NULL!
=func)
func();
FreeLibrary(h);
return0;
}
首先定义函数指针类型,然后实例化一个该类型的函数。
最后调用即可。