Windows核心编程_动态链接库_DLL基础_DLL与进程的地址空间

本文主要是介绍Windows核心编程_动态链接库_DLL基础_DLL与进程的地址空间,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

通常创建一个DLL要比建立一个应用程序容易,因为DLL包含一组可以被任何应用所使用的自治(autonomous)函数。在DLL中通常没有支持处理消息循环或创建窗口的代码。一个DLL只是一组源代码模块的集合。其中每个模块包含应用程序(可执行文件)或另一个DLL将要调用的一组函数。当所有的源代码文件编译后,就像应用程的可执行文件那样被链接程序所链接。然而,对于一个DLL,必须要为链接程序设定DLL开关选项。该选项使得链接程序向生成的DLL文件映像发出略有差异的信息,这样,操作系统装载程序就可以将该文件映像识别为一个DLL,而不是应用程序。
在应用程序(或另一个DLL)可以调用DLL中的函数之前,DLL的文件映射必须映射到调用进程的地址空间。可以采用两种方法来完成这项操作:隐式的装载时链接或显示的运行时链接,隐式链接在本章后续部分加以讨论,显示链接将在第20章中进行讨论。
一旦DLL的文件映射到调用进程的地址空间,则DLL中的函数对于运行在该进程内的所有线程都是可用的。实际上DLL几乎失去了它作为DLL的所有特征标志。对于进程中的线程而言,DLL的代码和数据开起来就像是恰好存在于进程地址空间中的额外代码和数据。当一个线程调用DLL函数时,该函数查看线程的栈以检索被传递的参数,并且将线程的栈空间用于它所需要的任意局部变量。另外,被DLL中的函数代码所创建的任何对象都属于调用它的线程或进程——一个DLL并不拥有任何元素。
例如,如果DLL中的一个函数所调用VirtualAlloc,则将从调用线程的进程地址空间中保留该地址空间的区域。如果后来从进程的地址空间中取消DLL的映射,则该地址空间的区域仍然会保留,因为系统并没有跟踪记录这样一个事实:DLL中的函数保留着该区域。被保留的地址空间区域是属于调用进程的,只有当一个线程调用VirtualFree函数或该进程终止时,该保留区域才会释放。
一个可执行文件中的全局变量和静态变量不能被该可执行文件的多个运行实例所共享。在Windows 98中,是通过当可执行文件映射到进程的地址空间时,为该文件的全局变量和静态变量分配存储空间的机制来保证这一点的;而在Windows 2000中,则是通过第13章中讨论的写时复制(copy-on-write)机制来加以保证的。一个DLL中的全局变量和静态变量是以相同的方式处理的。当一个进程把一个DLL的映射文件映射到其地址空间时,系统将同时创建全局数据变量和静态数据变量的实例。
注意:需要引起重视的是,一个单独的地址空间是由一个可执行模块和若干个DLL模块组成的。其中的一些模块可以链接到一个静态版本的C/C++运行时库,还有一些模块可能链接到一个DLL版本的C/C++运行时库,而另外一些模块(如果不是用C/C++编写的)可能根本就不需要C/C++运行时库。许多开发人员都存在一个错误的认识,因为他们忘记了若干个C/C++运行时库可能会存在于一个单一的地址空间中。研究下面的代码:

PVOID DLLFunc()
{// Allocate bloc from DLL's C/C++ run-time heapreturn malloc(100);
}VOID EXEFunc()
{PVOID pv = DLLFunc();// Access the storage pointed to by pv...// Assumes that pv is in EXE's C/C++ run-time heapfree(pv);
}

那么你是怎样考虑的呢?上述代码能够正确运行吗?DLL中的函数所分配的块是否被EXE中的函数所释放?答案是:可能会是这样!因为上述代码并没有提供足够的信息。如果EXE和DLL这两者都链接到DLL版本的C/C++运行时库,则对free调用将会失败。我曾多次见过开发人员编写出类似的代码,结果是毁了代码。
有一个简单的方法可以解决这个问题。当一个模块提供了分配内存的函数时,该模块必须同时提供一个释放内存的函数。重写上述代码如下:

PVOID DLLFunc()
{// Allocate bloc from DLL's C/C++ run-time heapreturn malloc(100);
}VOID DLLFreeFunc(PVOID pv)
{// Free bloc form DLL's C/C++ run-time heapreturn free(pv);
}VOID EXEFunc()
{PVOID pv = DLLFunc();// Access the storage pointed to by pv...// Assumes that pv is in EXE's C/C++ run-time heapfree(pv);
}

经过重写后的代码是正确的,它总是可以正确地执行。当编写一个模块时,不要忘记其它模块中的那些函数,它们甚至可能不是用C/C++编写的,因此可能不会使用malloc和free函数进行内存分配。注意不要在代码中设定这些假设条件。顺便提及,当调用malloc和free函数时,该结论对于C++的new和delete操作符也是相同的。

这篇关于Windows核心编程_动态链接库_DLL基础_DLL与进程的地址空间的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1036067

相关文章

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

Spring的基础事务注解@Transactional作用解读

《Spring的基础事务注解@Transactional作用解读》文章介绍了Spring框架中的事务管理,核心注解@Transactional用于声明事务,支持传播机制、隔离级别等配置,结合@Tran... 目录一、事务管理基础1.1 Spring事务的核心注解1.2 注解属性详解1.3 实现原理二、事务事

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

深入浅出Java中的Happens-Before核心规则

《深入浅出Java中的Happens-Before核心规则》本文解析Java内存模型中的Happens-Before原则,解释其定义、核心规则及实际应用,帮助理解多线程可见性与有序性问题,掌握并发编程... 目录前言一、Happens-Before是什么?为什么需要它?1.1 从一个问题说起1.2 Haht

Oracle数据库在windows系统上重启步骤

《Oracle数据库在windows系统上重启步骤》有时候在服务中重启了oracle之后,数据库并不能正常访问,下面:本文主要介绍Oracle数据库在windows系统上重启的相关资料,文中通过代... oracle数据库在Windows上重启的方法我这里是使用oracle自带的sqlplus工具实现的方

MySQL8.0临时表空间的使用及解读

《MySQL8.0临时表空间的使用及解读》MySQL8.0+引入会话级(temp_N.ibt)和全局(ibtmp1)InnoDB临时表空间,用于存储临时数据及事务日志,自动创建与回收,重启释放,管理高... 目录一、核心概念:为什么需要“临时表空间”?二、InnoDB 临时表空间的两种类型1. 会话级临时表