app教程网 综合百科 dll文件有什么作用(dll文件详解)

dll文件有什么作用(dll文件详解)

较大的应用程序由许多模块组成,这些模块分别执行相对独立的功能,它们相互配合完成整个软件系统的工作。可能会有一些具有通用功能的模块,在构建其他软件系统时仍然会用到。当构建软件系统时,

如果把所有模块的源代码都静态编译成整个应用程序EXE文件,会有一些问题:一个缺点是会增加应用程序的大小,程序运行时会占用更多的磁盘空间,消耗更多的内存空间。

导致系统资源的浪费;另一个缺点是,在编写大型EXE程序时,每次修改和重建都必须对所有源代码进行调整和编译,增加了编译过程的复杂性,也不利于周期性的单元测试。

Windows系统平台提供了一个完全不同的有效的编程和运行环境。您可以将独立的程序模块创建为较小的DLL(动态链接库)文件,并单独编译和测试它们。

在运行时,只有当EXE程序真正想要调用它们时,系统才会将这些DLL模块加载到内存空间中。这种方法不仅减少了EXE文件的大小和对内存空间的需求,

而且使这些DLL模块能够被多个应用程序同时使用。Windows本身以DLL模块的形式实现了一些主要的系统功能。

一般来说,DLL是一种磁盘文件,可以。dll,DRV。丰,SYS和许多带有。EXE作为扩展名。它由全局数据、服务功能和资源组成。

在运行时,它被系统加载到调用进程的虚拟空间中,成为调用进程的一部分。如果与其他dll没有冲突,文件通常被映射到进程的虚拟空间中的同一个地址。DLL模块包含各种导出函数,向外界提供服务。

DLL可以有自己的数据段,但不能有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现代码封装;DLL的编译与具体的编程语言和编译器无关。

在Win32环境中,每个进程都复制自己的读/写全局变量。如果要与其他进程共享内存,必须使用内存映射文件或声明一个共享数据段。DLL模块所需的堆栈内存是从运行进程的堆栈中分配的。

Windows在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。Windows操作系统对DLL的操作只是将DLL映射到需要它的进程的虚拟地址空间。

DLL函数中的代码创建的任何对象(包括变量)都属于调用它的线程或进程。

呼叫模式

1.静态调用方式:编译器系统在应用程序结束时完成加载DLL和卸载DLL的编码(如果有其他程序使用该DLL,则Windows对该DLL的应用记录减1,

直到所有相关程序都使用完该DLL,它才被发布,该DLL简单实用,但不够灵活,无法满足一般要求。

隐式调用:您需要添加。生成应用程序项目的动态链接库时生成的LIB文件。当你想使用DLL中的函数时,你只需要解释它。

隐式调用不需要调用LoadLibrary()和FreeLibrary()。当程序员创建一个DLL文件时,链接器会自动生成一个对应的LIB导入文件。

该文件包含每个DLL导出函数的符号名和可选标识号,但不包含实际代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。

程序员通过静态链接编译生成应用程序时,应用程序中的调用函数与LIB文件中导出的符号相匹配,这些符号或标识号进入生成的EXE文件。

LIB文件还包含相应的DL L文件名(但不是完整的路径名),该文件名由链接器存储在EXE文件中。

当应用程序需要加载DLL文件时,Windows根据这些信息找到并加载DLL,然后通过符号名或标识号动态链接DLL函数。

加载应用程序EXE文件时,应用程序调用的所有DLL文件都将被加载到内存中。可执行程序链接到输入库文件(。lib文件),包含有关DLL输出函数的信息。

操作系统在加载可执行程序时加载DLL。可执行程序通过函数名直接调用DLL的输出函数,调用方法与程序内部其他函数相同。

2.动态调用方式:程序员用API函数加载和卸载DLL,达到调用DLL的目的,使用起来比较复杂,但可以更有效地利用内存,是编译大型应用程序的重要方式。

显式调用:指在应用程序中用MFC提供的LoadLibrary或AfxLoadLibrary在自己制作的动态链接库中显式调用,动态链接库的文件名就是上述两个函数的参数。

然后用GetProcAddress()得到你要引入的函数。从那时起,您可以调用这个传入函数,就像它是这个应用程序的自定义函数一样。在应用程序退出之前,

应该使用MFC提供的FreeLibrary或者AfxFreeLibrary来释放动态链接库。直接调用Win32的LoadLibary函数,并将DLL的路径指定为参数。

LoadLibary返回应用程序在调用GetProcAddress函数时使用的提示参数。GetProcAddress函数将符号名或标识号转换成DLL中的地址。

程序员可以决定何时加载或不加载DLL文件,显式链接决定在运行时加载哪个DLL文件。使用DLL的程序在使用它之前必须加载DLL以获得DLL模块的句柄。

然后调用GetProcAddress函数获取输出函数的指针,退出前必须卸载DLL(FreeLibrary)。

Windows将按照下列搜索顺序查找DLL:

包含EXE文件的目录进程的当前工作目录Windows系统目录Windows目录是MFC中Path环境变量DLL中列出的一系列目录。

非MFC DLL:指不使用MFC类库结构,直接用C语言编写的DLL,其输出函数一般使用标准C接口,可以被非MFC或MFC编写的应用程序调用。

常规DLL:和下面描述的扩展DLL一样,是用MFC类库写的。明显的特点是源文件中有一个继承CWinApp的类。

可以细分为静态连接MFC和动态连接MFC。静态连接MFC的动态连接库只有VC的专业版和企业版支持。

任何Win32程序都可以使用这种DLL应用程序中的输出函数,包括使用MFC的应用程序。输入函数具有以下形式:

extern 'C' EXPORT YourExportedFunction();

没有extern 'C '修饰,输出函数只能从C代码调用。

DLL应用程序是从CWinApp派生的,但是没有消息循环。

动态链接到MFC的常规DLL应用程序中的输出函数可由任何Win32程序使用,包括使用MFC的应用程序。但是,DLL的所有函数输出都应该以下面的语句开始:

afx _ manage _ state(afxgetstaticmodulestate())该语句用于正确切换MFC模块状态。

用支持DLL技术的所有语言编写的应用程序都可以调用常规DLL。在这个动态链接库中,它必须有一个继承自CWinApp的类,DLLMain函数由MFC提供。

不一定要自己明确写出来。

扩展DLL:用来复用从MFC继承的类,也就是这种类型的动态链接库可以用来输出从MFC继承的类。

它输出的函数只能由使用MFC并动态链接到它的应用程序使用。可以从MFC中继承更适合自己使用的类,提供给自己的应用程序。

也可以随意为应用程序提供MFC或MFC继承类对象指针。扩展DLL是通过使用MFC的动态链接版本创建的,它仅由使用MFC类库编写的应用程序调用。

扩展dll不同于常规dll,因为它没有从CWinApp继承的类对象,所以必须为DLLMain函数添加初始化代码和结束代码。

与常规DLL相比,有以下不同之处:

1.它没有从CWinApp派生的对象;

2、它必须有一个DLLMain 函数;

3、DLLMain 调用AfxInitExtensionModule 函数,必须检查该函数的返回值,如果返回0,DLLMmain 也返回0;

4、如果它希望输出CRuntimeClass 类型的对象或者资源,则需要提供一个初始化函数来创建一个CDynLinkLibrary 对象。并且,有必要把初始化函数输出;

5、使用扩展DLL 的MFC 应用程序必须有一个从CWinApp 派生的类,而且,一般在InitInstance 里调用扩展DLL 的初始化函数。

DLL入口函数

1、每一个DLL 必须有一个入口点,DLLMain 是一个缺省的入口函数。DLLMain 负责初始化和结束工作,每当一个新的进程或者该进程的新的线程访问DLL 时,

或者访问DLL 的每一个进程或者线程不再使用DLL或者结束时,都会调用DLLMain。但是,使用TerminateProcess 或TerminateThread 结束进程或者线程,

不会调用DLLMain。

DLLMain的函数原型:

BOOL APIENTRY DLLMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) { switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: . case DLL_THREAD_ATTACH: . case DLL_THREAD_DETACH: . case DLL_PROCESS_DETACH: . return TRUE; } }

参数:

hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);

ul_reason_for_call:是一个说明动态库被调原因的标志。当进程或线程装入或卸载动态连接库的时

本文来自网络,不代表本站立场,转载请注明出处:https: