现在的位置: 首页 > 综合 > 正文

dll相关

2018年04月30日 ⁄ 综合 ⁄ 共 2382字 ⁄ 字号 评论关闭
 windows可执行文件呈现两种形式:程序和DLL。

静态链接:
连接器从一个DELPHI编译单元中取出例程的编译代码,并将它添加到应用程序的代码上。最终的可执行文件将包含应用程序和各个相关单元的所有代码。在程序运行时,代码和数据的位置对程序而言是已知的。这种认知是在编译时就确定好的。DELPHI的连接器是非常聪明的,它只从应用程序所涉及的单元中提取出最少数量的代码,而且只链接得到实际使用的函数和方法。例外是虚方法的包含。编译器无法事先确定程序将要调用哪些虚方法,因此它必须全部包含这些虚方法。由于这一缘故,带有许多虚函数和库的程序往往会生成较大的可执行文件。

DLL:
连接器使用子例程的EXTERNAL声明中所包含的信息来创建可执行文件内的一个导入表。WINDOWS在将可执行文件装载到内存中时,首先装载所有必需的DLL,然后应用程序才启动。在这个装载过程中,WINDOWS用DLL函数在内存中的地址填写应用程序的导入表。如果由于某些原因而没有找到DLL,或者一个得到引用的了例程没有出现在找到的DLL中,则应用程序将不启动。

每当应用程序调用一个外部函数时,它就使用这个导入表将调用转发给DLL代码。DLL已经变成了运行程序的一部分,并被装载在同一个地址空间中。所有的参数传递均发生在应用程序的栈上(DLL没有一个单独的堆栈),或者发生在CPU寄存器中。DLL和它所产生的全局数据的任何内存分配都将驻留在主进程的地址空间内。因而,数据和内存指针能够直接从DLL被传递给应用程序,反之亦然。

如果不同的程序使用同一个DLL,那么只需将这个DLL装载到内存中一次即可,从而节省系统内存。DLL被映射到每个进程(每个正在运行的应用程序)的私有地址空间内,但它们的代码到内存中的装载只需进行一次。

程序员可以提供一个DLL的不同版本,代替当前的DLL,而且无需重新编译正在使用当前DLL的应用程序。当然,这一技巧只有当DLL中的函数与前一个版本有相同的参数时才管用。即使DLL有了新的函数也无关紧要。只有当DLL的较旧版本中的一个函数在新版本中不存在。特别适用于复杂的应用程序。如果程序员有一个非常大而且要求频繁更新或缺陷纠错的应用程序,可以将它分解成一些可执行文件和DLL,这样程序员就能够分布那些修改过的部分,而不是分布单个大的可执行文件。这么做对WINDOWS系统库来说格外有意义。

另一个常见的技巧是使用DLL来专门存储资源。程序员可以建立一个DLL的不同版本来包含用于不同语言的字符串,然后在运行时改变语言;也可以准备一个包含图标与位图的库,然后将这些图形元素用在不同的应用程序中。开发一个程序的专用语言版本是特别重要的。

DLL独立于编程语言,允许程序员调用被存储在DLL中的函数。然而,这一灵活性只适用于函数的使用。当程序员需要共享类和对象时,编程语言之间的差别会引起许多麻烦。为了共享一个跨编程语言的库中的对象,MICROSOFT首先推出了COM基础结构和现在的。NET体系结构,目标是以一种语言独立的方式处理和共享对象

导出的函数应该被声明为STDCALL,以便使用标准的WIN32参数传递技巧来替代优化的REGISTER参数传递技巧(这是DELPHI中的默认设置)。这条规则的例外情况是如果程序员只打算从其它DELPHI应用程序中使用这些库。

DLL的参数类型应该是默认的WINDOWS类型(大部分是C兼容的数据类型),如果程序希望能够将DLL用在其它开发环境中。

所有的API函数都被声明在WINDOWS系统单元中。

DELPHI包含了大量的WINDOWS API的DELPHI语言转换。

当程序的某一部分代码需要频繁地改变时,建立一个DLL是非常有帮助的。在这种情况下,可以经常替换DLL,同时让程序的其它部分保持不变。同样,当需要编写一个给不同用户组提供不同特性的应用程序时,可以给那些用户分发一个DLL的不同版本。

在WINDOWS中动态装载一个DLL通过调用LOADLIBRARY API函数实现。
如果库被找到并得到装载,调用GETPROCADDRESS API函数,该函数查找DLL的导出表,进而查找作为参数传入的函数名称。如果发现了一个匹配,将返回一个指向被请求过程的指针。

最后调用FREELIBRARY函数,以便DLL能够从内存中得到适当的释放。事实上,系统为库使用一个引用计数技巧,以便在每个装载请求与一个释放请求匹配起来时,释放那些库。

静态调用DLL,如果程序在启动时无法找到指定的DLL,则系统会报错后退出。
动态调用DLL,效率较低、速度较慢,但不会因为缺少某个DLL而使程序无法运行,而只是缺少某种功能而已。

如果多个应用程序使用同一个DLL,则DLL只需要装入内存一次,节省系统内存,节省装入时间。

DLL不是EXE,将其装载到内存中并不会直接导致运行,而只能等待主程序对其进行调用。

对于复杂的应用程序,将其分解为多个DLL更容易调试,也更容易找到错误的根源。

external关键字表示该函数不是此程序中实现的,而是由外部DLL实现的。

dll的导出函数必须位于export子名中。

导出函数的定义应尽量使用stdcall规范,以保证非Delphi程序也可以使用它。


该技术经常被黑客和一些恶意的病毒制造者来进行刺控和代码注入。
能够预演和修改系统事件和消息,并能在系统范围内阻止事件和消息的发生。
windows操作系统支持多种不同类型的钩。
操作系统为每种类型的钩都维护一个钩链(hook chain)。钩链是类指针列表,每个指针都指向由应用程序定义的钩过程(hook procedure)的特殊回调函数。
对于全局钩过程,必须使用DLL实现。
在应用程序终止前必须调用unHookWindowsHookEx函数释放钩占用的系统资源,这一过程称为脱钩(unHook)。

【上篇】
【下篇】

抱歉!评论已关闭.