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

相关文章

javafx 如何将项目打包为 Windows 的可执行文件exe

《javafx如何将项目打包为Windows的可执行文件exe》文章介绍了三种将JavaFX项目打包为.exe文件的方法:方法1使用jpackage(适用于JDK14及以上版本),方法2使用La... 目录方法 1:使用 jpackage(适用于 JDK 14 及更高版本)方法 2:使用 Launch4j(

windows端python版本管理工具pyenv-win安装使用

《windows端python版本管理工具pyenv-win安装使用》:本文主要介绍如何通过git方式下载和配置pyenv-win,包括下载、克隆仓库、配置环境变量等步骤,同时还详细介绍了如何使用... 目录pyenv-win 下载配置环境变量使用 pyenv-win 管理 python 版本一、安装 和

C#如何优雅地取消进程的执行之Cancellation详解

《C#如何优雅地取消进程的执行之Cancellation详解》本文介绍了.NET框架中的取消协作模型,包括CancellationToken的使用、取消请求的发送和接收、以及如何处理取消事件... 目录概述与取消线程相关的类型代码举例操作取消vs对象取消监听并响应取消请求轮询监听通过回调注册进行监听使用Wa

Python使用pysmb库访问Windows共享文件夹的详细教程

《Python使用pysmb库访问Windows共享文件夹的详细教程》本教程旨在帮助您使用pysmb库,通过SMB(ServerMessageBlock)协议,轻松连接到Windows共享文件夹,并列... 目录前置条件步骤一:导入必要的模块步骤二:配置连接参数步骤三:实例化SMB连接对象并尝试连接步骤四:

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]