1、dll文件详解dll文件详解DLL 文件详解Part1 dll文件与exe文件的区别:动态链接库(Dynamic Link Library,缩写为DLL)是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。动态链接库文件的扩展名一般是dll,也有可能是drv、sys和fon,它和可执行文件(exe)非常类似.具体说:DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用程序直接或间接调用。动态链接是相对于静态链接而言的。所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过程的代码就在程序的exe文件中,该文
2、件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。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派生类。三者区别
3、展开来说: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基础类库
4、类派生的可重用类的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函数,并在
5、那里执行任何必需的初始化。 扩展DLL是使用MFC动态链接库版本(也称作共享MFC版本)生成的。只有用共享MFC版本生成的MFC可执行文件 (应用程序或规则DLL)才能使用扩展DLL。客户端应用程序和扩展DLL必须使用相同版本的MFCx0.dll。使用扩展DLL,可以从MFC派生新的自定义类,然后将此“扩展”版本的MFC提供给调用DLL的应用程序。具体执行时,主要是资源的管理:mfc扩展dll会把当前dll的句柄加入一个全局资源句柄列表。而普通的dll则不会。即使支持mfc也不会,这样你每次用mfc类创建资源的时候要多写几行代码 。但你用在mfc扩展dll用win32来访问资源也需要多写代码。
6、=扩展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) 返回值 函数名(形式参数
7、声明) AFX_MANAGE_STATE ( AfxGetStaticModuleState() );/第一条语句 . /在def模块文件中声明函数序号 EXPORTS 导出函数名 序号数字 常规DLL客户方的隐式函数声明头文件:=另外,所有的动态链接库都有两种链接方式:隐式调用和显示调用。隐式调用编译程序时需要头文件、lib文件,运行时需要DLL文件,并且运行过程中DLL文件一直被占用。显式调用编译时什么都不需要,在需要使用DLL中的函数时,通过LoadLibrary()和FindProcAdress()这两个API调用。只需要一个DLL文件即可,而且在需要使用的时候DLL才被占用,使用完毕
8、即被解除占用。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#inc
9、lude MyDll.hBOOL 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文件中
10、添加如下几行:以下是引用片段:#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)工程,工程名为MF
11、CDll,选择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.dll2.使用方法(1)隐式调用法: 将MFCDll.lib拷贝到需要应用该DLL的工程的目录下,将MyDll.dll拷贝到产生的应用程序的目录下,并在需要应用该DLL中的函数的CPP文件中添加如下几行:/注意这里
12、没有在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文件头文件中一般如此:
13、#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 ex
14、tern 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 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; 首先定义函数指针类型,然后实例化一个该类型的函数。最后调用即可。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1