关闭

动态链接库(dynamic link library ,DLL)

标签: dlllibrary编译器windowsvariablesheader
996人阅读 评论(0) 收藏 举报
动态链接库(dynamic link library ,DLL)基础知识

动态链接库(dynamic link library ,DLL)一直以来都是操作系统的基石,Windows应用程序编程接口(aplication programming interface API)提供的所以函数都包含在DLL中,其中三个最重要的DLL分别是:Kernel32.dll,包含用来管理内存,进程以及线程;User32.dll,包含的函数用来执行与用户界面相关的任务,如创建窗口和发送消息;GDI32.dll,包含的函数用来绘制图像和显示文字.windows还提供了其他一此DLL,用来执行更加专门的任务.如AdvAPI32.dll包含的函数与对像的安全性,注册表的操控以及事件日志;ComDlg32.dll包含了一些常用的对话框,comcttl32.dll支持所有常的窗口控件.


DLL的好处在于以下几点:
1.综扩展了应用程序的特性;
2.它简化了项目管理;
3.它有助于节省内存,如果两个惦的应用程序使用同一个DLL,那么些DLL只需要截稿内存一次,之后所有的应用程序就可以共享些DLL在内存中的页面.
4.它促进了资源的共享,DLL能包含诸如对话框模板,字符串,图标以及位图类的资源.多个应用程序可以使用DLL来共享这些资源.
5.它促进了本地化,DLL常用常用用来对应用程序进行本地化.例如一个应用程序可以只包含代码但不包含用户界面组件,DLL用来存放本地化的用户界面组件,供应用程序载入使用.
6.它们有助于解决平台间的差异.不用的版本的windows提供了不同的函数.
7.它们可以用于特殊目的.windows提供的某些特性只有DLL才能使用.例如我们可以(通过使用windowsHookEx和SetWinEventHook来)安装某些挂钩函数,介前提条件是必须将挂钩函数通知函数放在DLL中.我们可以创建COM对象来对windows的资源管理器的外壳进行扩展,但COM对象必须被存放在DLL中.


下面将介绍如何在自己的应用程序中创建DLL:
创建DLL比创建应用程序容易,因为DLL通常由一组可以供任何应用程序使用的独立函数组成.在DLL中通常没有用来处理消息循环或创建窗口的代码.DLL只不过是一组源代码模块,每个模块包含一些可供应用程序或其他DLL调用的函数.在所有的源文件编译完成之后,链接器会像链接应用程序的可执行文件那样,对他们进行链接.但在创建DLL的时个我们必须给链接器指定DLL开关,这个开关会使链接器在生成DLL文件映像中保存一些与可执行文件略微不同的信息.这样操作系统的加载程序就能够将文件映像识别为DLL.而不会将它识别为应用程序.在应用程序能够调用一个DLL中的函数之前必须将些DLL的文件映像映射到调用进程的地址空间中.映射会为隐式载入和显示链接.一早系统将一个DLL文件映像映射到调用进程的地直空间中之后,进程中的所有线程就可以调用些DLL中的函数了.事实上,些DLL几乎完全丧失了它的DLL微分:对进程中的线程来说,些DLL中的代码就像是一引起附加的代码和数据,碰巧被放在进程地直空间中,当纯种调用DLL中的一个函数的时候 ,些函数会在线程栈中取得传给它的参数,将使用线程栈来存放它需要的局部变量.此外,些DLL的函数创建的任何对象专利申请调用线程或调用进程拥有--DLL绝对不会拥有任何对象.如果一个可执行模块需要从另一个DLL模块中导入函数和变量,我们必须先构奸该DLL模块,然后不规则构建本身这个可执行模块,

构建DLL需要以下步骤:
1.必须构建一个头文件,在其中之一包含我们想要在DLL中导出的函数原型,结构以及符号.为了构建些DLL,DLL的所以资源文件都包含这个头文件.2.创建C/C++源文件来实现想要在DLL模块中导出的函数和变量.由于在构建可执行模块的时候不需要这些源文件,因此创建该DLL的公司可以将这些源代码作为公司的机密.
3.在构建些DLL模块的时候,编译器会对每个源文件进行处理产生一个.OBJ模块,每个源文件对应一个.OBJ文件.
4.当所有.OBJ都创建完毕后,外国投资器会将所有.OBJ模块的内容合并起来,产生一个单独的DLL映像文件,这个映像文件(或模块)包含中所有的二进制代码以及全局静态变量.为了执行模块,这个文件是必需的.
5.如果链接器检测到DLL的源文件输出了至少一个函数或变量,那么链接器还会生成一个.LIB文件,这个.LIB文件非常小,这是因为它并不包含任何函数或变量,它只是列出所有被导出所有被导出的函数和变量的符号铝.为了构建可执行模块这个文件是必需的.

一旦构建了DLL模块我们就可以通过下列步聚来构建可执行模块:
1.在在所有引用了心出函数,变量,数据结构或符号的源文件中,必须包含由DLL的开发人吊所创建的头文件.
2.创建C/C++源文件中实现想要包含在可执行模块中的函数和变量.当然代码可以引用在DLL的头文件中定义的函数和变量.
3.在构建可执行模块的时候,编译器会对每个人源文件进行处理并产生一个.OBJ模块.
4.当所有.OBJ模块都创建完毕后,外国投资器会将所有的.OBJ模块内债合并起来,产生一个单独的单独的可执行映像文件.这个映像文件包含了可执行文件中所有的二进制代码以及全局/静态变量.此可执行模块还包含一个导入段(import section),其中列出了所有它需要的DLL模块的名称.此外,对列出的每个DLL,此段还记录了可执行文件的二进制代码从中引用的函数和变量的符号名.操作系统的加载程序会解析这个导入段.

5.加载程序先为的进程创建一个虚拟地址空间,并将可执行模块映射到新进程的地址空间中.加载程序接着解析可执行模块的导入
例:
/****************************************************************************
Module:mylib.h
*****************************************************************************/
#ifdef MYLIBAPI
//MYLIBAPI should be defined in all of the DLL's source
//code modules before this header file is included
// all functions/variables are being exported
#else
//this header file is included by an EXE soure code module
//indicate that all functions/variables are being imported
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif
//define any data structures and symbols here
//define exported variables here ,(NOTE: avoid exporting variables.)
MYLIBAPI int g_nResult;
//define exported function prototypes here;
MYLIBAPI int Add(int nLeft,int nRight);
////////////////////////end of file///////////////////////////

在编译前面的DLL源文件的时候,MYLIBAPI在包含MyLib.h关文件之前被定义为__decslpec(dllexport).如果编译器找不到一个变量,函数或C++类是用__decslpec(dllexport)修饰的,那么它就知道应该在生成的DLL模块中导出此变量,函数或者C++类,

注意,对于那些要导出的函数和变量定义的前面一定要加上MYLIBAPI标识符,另外要注意的是:在源文件中,不必在要被导出的变量和函数前面加MYLIBAPI,这里不需要MYLIBAPI的原因编译器在解析头文件的时个会雇应该导出哪些变量或者函数。另外MYLIBAPI符号包含了解extern "c"修饰符,只有在编写C++代码的时候才需要加这个修饰符,在编写C代码的时候不应该加些修饰符,C++编译器通宵会对函数名和变量进行改编(mangle),这在链接的时候会导致严重的问题。例如:假设一个DLL是用C++编译的,而可执行文件是用C编写的,在构建DLL的时候编译器会对函数名进行改变,但在构建的时候,会发再可执行文件引用了一个不存在的函数名进行改编,但在构建可执行文件的进修,编译器不会对函数名进行改编,当链接时会发现文件不存在。extern"c"用来告诉编译器不要对变量名或函数名进行改编,这样用C,C++或任何编程语言编写的可执行模块都可以访问些变量或函数。
/*****************************************************************************

MyLibFile.cpp

*****************************************************************************/
#include <Windows.h>
#define MYLIBAPI extern "C" __declspec(dllexport)
#include "MyLib.h"


#endif
int g_nResult ;
int Add(int nLeft,int nRight){
g_nResult=nLeft+nRight;
return(g_nResult);
}
////////////////////////////end of file //////////////////////////////////////////
可执行文件不应该在包含这个头文件这前定义MYLIBAPI,由于MYLIBAPI未定义,因此头文件将MYLIBAPI定义为__declspec(dllexport),这样编译器知道该项可执行文件的源文件要从DLL模块中导入一些变量和函数。

 

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:10314次
    • 积分:189
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:4篇
    • 译文:0篇
    • 评论:3条
    文章分类
    文章存档
    最新评论