《Windows核心编程》读书笔记(14) 第19章 DLL基础

第19章 DLL基础

3个最重要DLLKernel32.dll,它包含用于管理内存、进程和线程的各个函数;User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;GDI32.dll,它包含用于画图和显示文本的各个函数。

如果两个或多个应用程序使用同一个DLL,那么该DLL的页面只要放入RAM一次,所有的应用程序都可以共享它的各个页面。

DLL与进程的地址空间

DLL只是一组源代码模块

在应用程序(或另一个DLL)能够调用DLL中的函数之前,DLL文件映像必须被映射到调用进程的地址空间中。

当一个线程调用DLL函数时,该DLL函数要查看线程的堆栈,以便检索它传递的参数,并将线程的堆栈用于它需要的任何局部变量。

DLL中函数的代码创建的任何对象均由调用线程所拥有,而DLL本身从来不拥有任何东西。

可执行文件的全局变量和静态变量不能被同一个可执行文件的多个运行实例共享。

当一个进程将DLL的映像文件映射到它的地址空间中去时,系统将同时创建全局数据变量和静态数据变量的实例。

有些可以链接到静态版本的C/C++运行期库,有些可以链接到一个DLL版本的C/C++运行期库,而有些模块(如果不是用C/C++编写的话)则根本不需要C/C++运行期库。许多开发人员经常会犯一个常见的错误,因为他们忘记了若干个C/C++运行期库可以存在于单个地址空间中。请看下面的代码:

PVOID DLLFunc(){
    //Allocate block from DLL's C/C++ run-time heap
    return (malloc(100));
}

VOID EXEFunc()
{ 
    PVOID pv = DLLFunc();
    //Access the sortage pointed by pv 
    //Assume that pv is in EXE's C/C++ run-time heap 
    free(pv);
}

DLL的总体运行情况

创建DLL模块

只有当你编写C++代码而不是直接编写C代码时,才能使用extern“C”修改符

C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。

如果使用extern“C”,就可以告诉编译器不要改变变量名或函数名,这样,变量和函数就可以供使用CC++或任何其他编程语言编写的可执行模块来访问。

 

创建可执行模块

当创建可执行源代码文件时,必须加上DLL的头文件。    

当编译器看到修改变量、函数或C++类的__declspec(dllimport)时,它知道这个符号是从某个DLL模块输入的。

链接程序必须将所有.obj模块组合起来,创建产生的可执行模块。该链接程序必须确定哪些DLL包含代码引用的所有输入符号的DLL。因此你必须将DLL.lib文件传递给链接程序。如前所述,.lib文件只包含DLL模块输出的符号列表。链接程序只想知道是否存在引用的符号和哪个DLL模块包含该符号。如果连接程序转换了所有外部符号的引用,那么可执行模块就因此而产生了。

当链接程序进行输入符号的转换时,它就将一个称为输入节的特殊的节嵌入产生的可执行模块。输入节列出了该模块需要的DLL模块以及由每个DLL模块引用的符号。

使用VisualStudioDumpBin.exe实用程序(带有-imports开关),能够看到模块的输入节的样子。

运行可执行模块

当一个可执行文件被启动时,操作系统加载程序将为该进程创建虚拟地址空间。然后,加载程序将可执行模块映射到进程的地址空间中。加载程序查看可执行模块的输入节,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中。

由于该输入节只包含一个DLL名而没有它的路径名。因此加载程序必须搜索用户的磁盘驱
动器,找出DLL。下面是加载程序的搜索顺序:
1)包含可执行映像文件的目录。
2)进程的当前目录。
3)Windows系统目录。
4)Windows目录。
5)PATH环境变量中列出的各个目录。当DLL模块映射到进程的地址空间中时,加载程序要检查每个DLL的输入节。如果存在输入节(通常它确实是存在的),那么加载程序便继续将其他必要的DLL模块映射到进程的地址空间中。加载程序将保持对DLL模块的跟踪,使模块的加载和映射只进行一次(尽管多个模块需要该模块)。

 

当代码引用一个输入符号时,它将查看调用模块的输入节,并且捕获输入符号的地址,这样它就能够成功地访问输入变量、函数或C++类的成员函数。

 

这需要加载程序花费相当多的时间来加载这些DLL模块,并用所有使用输入符号的正确地址来调整每个模块的输入节。由于所有这些工作都是在进程初始化的时候进行的,因此应用程序运行期的性能不会降低。不过,对于许多应用程序来说,初始化的速度太慢是不行的。为了缩短应用程序的加载时间,应该调整你的可执行模块和DLL模块的位置并且将它们连接起来。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值