1.什么是内存映射文件

如上图:内存映射文件意思就是吧一个硬盘上的文件映射到物理页上在把物理页映射到虚拟内存上。

这样的好处是不必再打开、关闭文件,直接像访问自己的内存一样想读就读想写就写,想要读写文件时候就直接读写内存。还有一个很大的优点就是当文件很大的时候使用这种方式会有很好的性能。

下面我们尝试用代码实现

介绍下CreateFileMapping()函数,这个可以理解为准备物理内存的。在之前的物理内存中我们也知道,这个函数是来实现多个进程公用物理页的。他还可以把硬盘上的内容映射到物理页上(把文件句柄)

HANDLE CreateFileMappingA([in]           HANDLE                hFile,[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,[in]           DWORD                 flProtect,[in]           DWORD                 dwMaximumSizeHigh,[in]           DWORD                 dwMaximumSizeLow,[in, optional] LPCSTR                lpName
);

MapViewOfFile()函数:把物理内存与虚拟内存关联(就是最上面图中左边的箭头)

当执行完后我们会得到一个地址,我们代码中得到的就是虚拟内存的地址。然后我们就可以使用这个地址了。(下面我们读取地址)

LPVOID MapViewOfFile([in] HANDLE hFileMappingObject,[in] DWORD  dwDesiredAccess,[in] DWORD  dwFileOffsetHigh,[in] DWORD  dwFileOffsetLow,[in] SIZE_T dwNumberOfBytesToMap
);
#include"stdafx.h"
#include<stdio.h>
#include<Windows.h>
DWORD MappingFile(LPSTR lpcFile)
{HANDLE hFile;HANDLE hMapFile;DWORD dwFileMapSize;LPVOID lpAddr;
​//1.得到文件句柄hFile = CreateFileA(lpcFile,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE){printf("CreateFile 失败:%d \n", GetLastError());return 0;}
​//2.创建FileMapping对象hMapFile = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,NULL);if (hMapFile == NULL){printf("CreateFileMapping 失败:%d \n ", GetLastError());CloseHandle(hFile);return 0;}//3.映射到虚拟内存lpAddr = MapViewOfFile(hMapFile,FILE_MAP_COPY,//FILE_MAP_ALL_ACCESS FILE_MAP_COPY0, 0, 0);
​//4.读取文件DWORD dwTest1 = *(PDWORD)lpAddr;//读文件开始的地方DWORD dwTest2 = *((PDWORD)lpAddr + 0x30);//想读到哪(加上偏移)printf("%x %x \n", dwTest1, dwTest2);
}
int main(int argc, char* argv[])
​
{MappingFile("D:\\DebugView++CHS X32.exe");return 0;
}

我们用debugview++来测试看看。

我们先用wxmedit查看debugview++

代码中我们加了0x30.因为是DWORD类型,加1相当于加4。所以对应查看的应该是0xC0

看下输出

因为是小端。正好对应

下面是写文件:

#include"stdafx.h"
#include<stdio.h>
#include<Windows.h>
DWORD MappingFile(LPSTR lpcFile)
{HANDLE hFile;HANDLE hMapFile;DWORD dwFileMapSize;LPVOID lpAddr;
​//1.得到文件句柄hFile = CreateFileA(lpcFile,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,//打开现有文件FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE){printf("CreateFile 失败:%d \n", GetLastError());return 0;}
​//2.创建FileMapping对象hMapFile = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,NULL);if (hMapFile == NULL){printf("CreateFileMapping 失败:%d \n ", GetLastError());CloseHandle(hFile);return 0;}//3.映射到虚拟内存lpAddr = MapViewOfFile(hMapFile,FILE_MAP_COPY,//FILE_MAP_ALL_ACCESS FILE_MAP_COPY0, 0, 0);
​//4.读取文件//DWORD dwTest1 = *(PDWORD)lpAddr;//读文件开始的地方//DWORD dwTest2 = *((PDWORD)lpAddr + 0x30);//想读到哪(加上偏移)/*printf("%x %x \n", dwTest1, dwTest2);*///5.写文件*(PDWORD)lpAddr = 0x41414141;printf("A写入: %x\n", *(PDWORD)lpAddr);//强制更新缓存FlushViewOfFile(((PDWORD)lpAddr), 4);//6.关闭资源UnmapViewOfFile(lpAddr);CloseHandle(hMapFile);CloseHandle(hFile);
}
int main(int argc, char* argv[])
​
{MappingFile("D:\\DebugView++CHS X32.exe");return 0;
}

这个是写到了内存中,然后映射到文件中。

需要注意的是FileMapping对象为了保证效率不是实时写入。比如说:我们写文件执行后他不会立马改,他会写到缓存中。如果我们希望他立马改,我们可以强制跟新缓存。他可以立即把缓存写进文件中。

2.内存映射之共享

我们之前讲过两个进程共享一份物理内存,现在同时共享一个文件。

我们先创建一个文件

下面我们尝试在A进程中修改文件,再在B进程中读取。代码如下

A进程

#include"stdafx.h"
#define MAPPINGNAME "共享文件"
DWORD MappingFile(LPSTR lpcFile)
{HANDLE hFile;HANDLE hMapFile;DWORD dwFileMapSize;LPVOID lpAddr;
​//1.得到文件句柄hFile = CreateFileA(lpcFile,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,//打开现有文件FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE){printf("CreateFile 失败:%d \n", GetLastError());return 0;}
​//2.创建FileMapping对象hMapFile = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,MAPPINGNAME);if (hMapFile == NULL){printf("CreateFileMapping 失败:%d \n ", GetLastError());CloseHandle(hFile);return 0;}//3.映射到虚拟内存lpAddr = MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0, 0, 0);
​//4.读取文件//DWORD dwTest1 = *(PDWORD)lpAddr;//读文件开始的地方//DWORD dwTest2 = *((PDWORD)lpAddr + 0x30);//想读到哪(加上偏移)/*printf("%x %x \n", dwTest1, dwTest2);*///5.写文件*(PDWORD)lpAddr = 0x41414141;//修改文件(4个A)printf("A写入: %x\n", *(PDWORD)lpAddr);getchar();//强制更新缓存/*FlushViewOfFile(((PDWORD)lpAddr), 4);*///6.关闭资源UnmapViewOfFile(lpAddr);CloseHandle(hMapFile);CloseHandle(hFile);
}
int main(int argc, char* argv[])
​
{MappingFile("D:\\Test.txt");return 0;
}

B进程:

#include"stdafx.h"
#define MAPPINGNAME "共享文件"
int main()
{HANDLE hFile;HANDLE hMapFile;DWORD dwFileMapSize;LPVOID lpAddr;
​
​//1.打开FileMapping对象hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, MAPPINGNAME);if (hMapFile == NULL){printf("CreateFileMapping 失败:%d \n ", GetLastError());return 0;}//2.映射到虚拟内存lpAddr = MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0, 0, 0);
​//3.读取文件DWORD dwTest = *(PDWORD)lpAddr;printf("%x \n", dwTest);//4.释放资源UnmapViewOfFile(lpAddr);CloseHandle(hMapFile);return 0;
}

运行两个代码先A后B

读取到了:

发现文件被修改了


我们每一个进程启动时都会映射很多dll。这些dll在物理页上只有一份,而且每个进程都会用这些dll,操作系统不会为每个进程都单独分一块内存,这样就太浪费空间了。我们使用的内存有两种,私有和公有。我们使用的大多都是这种映射的公有的。所以无论是ntdll.dll还是user.dll在物理内存上都只有一份。进程使用时会映射到进程中。

我们刚刚讲到了,两个进程共享一个文件,读的时候没有问题。但是我们写的话怎么办呢?我们映射kerner32.dll是不是意味着我们能修改呢?大家用的是一份那么改的话是不是其他进程就受到影响了呢?

这样就会出现问题。但实际上不会这样。

我们看一下MapViewOfFile函数。其中我们映射文件时用到的是

这个。这个参数的意思是,当你修改时会再复制一个物理页。原来的物理页不变

如上图。当你试图改的时候会复制一个物理页,重新让你指向。你修改的就是复制的物理页。所以当你修改dll时对别人没影响。

Win32学习笔记(21)内存映射文件相关推荐

  1. C#内存映射文件学习总结

    C#内存映射文件学习 http://www.cnblogs.com/flyant/p/4443187.html 内存映射文件是由一个文件到进程地址空间的映射. C#提供了允许应用程序把文件映射到一个进 ...

  2. 内存映射文件——Windows核心编程学习手札之十七

    内存映射文件 --Windows核心编程学习手札之十七 与虚拟内存一样,内存映射文件保留地址空间,并将物理存储器提交给该区域,差别在于所提交的物理存储器是磁盘上有文件存在的空间,而非系统的页文件,一旦 ...

  3. windows笔记-内存映射文件

    Windows提供了3种进行内存管理的方法: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据. ...

  4. Win32汇编——内存映射文件

    1.概念.好处及原理:书P374 2.内存映射文件是多个进程进行通信的最有效的方法 3.使用函数: 创建内存映射文件对象:CreateFileMapping ,决定是在磁盘文件上建立内存映射文件还是在 ...

  5. java 内存映射文件进程间通讯_[转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile...

    进程间的通信方式有很多种, 上次我们说了最傻瓜的"共享外存/文件"的方法. 那么, 在本文中, 我们即将学习"共享内存"的方式实现进程间的通信, 这是IPC最快 ...

  6. 使用内存映射文件来提高你程序的性能

    本人在学习<WINDOWS核心编程>的时候对JEFFREY大师提到的一个小程序写了两个版本来比较性能,该程序的原始需求是这样的:对一个大文件进行倒序,也就是将一个文件头变成尾,尾变成头. ...

  7. 内存映射文件之剖析(一)

    内存映射文件之剖析 作者:xrbeck 内存映射文件(Mapping File)是Windows内存管理中的重要一环,也是编程 技术中比较高级的一个话题.目前关于这方面的资料比较少,而其实内存映射 文 ...

  8. 滴水逆向win32学习笔记1

    滴水逆向win32学习笔记 一.字符编码 基本介绍 关于utf-16.utf-8和unicode的关系 BOM头 二.宽字符 基本介绍 常用函数 三.Win32 API中的宽字符 什么是win32 A ...

  9. Win32学习笔记 第三章 HelloWin 选择自 villager 的 Blog

    Win32学习笔记 作者: 姜学哲(netsail0@163.net) 教材: Windows程序设计(第五版)北京大学出版社  [美]Charles Petzold 著  北京博彦科技发展有限公司 ...

  10. [python教程入门学习]python学习笔记(CMD执行文件并传入参数)

    本文章向大家介绍python学习笔记(CMD执行文件并传入参数),主要包括python学习笔记(CMD执行文件并传入参数)使用实例.应用技巧.基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋 ...

最新文章

  1. 程序可以在硬件之间发送吗_你知道硬件、软件工程师之间,还有一个固件工程师吗?...
  2. 基于Hadoop的大数据平台实施记——整体架构设计[转]
  3. A. Case of the Zeros and Ones
  4. stm32f405xx.h头文件的问题Undefined symbol IS_TIM_BREAK_INSTANCE
  5. python ssh
  6. 如何成为一名糟糕的程序员?
  7. fgo7.27服务器维护,【公告】更新游戏数据资料(7/27 实施)
  8. 战斗服务器响应超时是否尝试重连,刺激战场:教你,从开伞到落地瞬间技巧
  9. mysql desc show_MYSQL SHOW 用法
  10. 山东理工大学ACM平台题答案关于C语言 1231 绝对值排序
  11. LaTeX常用数学符号总结
  12. 文件(视频)上传到阿里云 java实现
  13. 高清录播系统与流媒体服务器,来同品牌全高清录播系统方案
  14. iOS两个强制旋转屏幕的方法
  15. creo三维生成二维图_proe5.0三维图转二维图
  16. 一级计算机电子表格人,计算机一级电子表格.doc
  17. Flex布局和gird布局
  18. 猪懂傻改之《powershell 代码规范》
  19. 【决策树算法】泰坦尼克号乘客生存预测
  20. 【Java】关于编程环境

热门文章

  1. 代理模式-CGLIB动态代理
  2. DEA数据包络分析python代码记录
  3. android 斜边_斜边计算器app下载|斜边计算器安卓版下载_v1.0.1_9ht安卓下载
  4. python爬取qq付费音乐程序_爬取QQ音乐(周杰伦)
  5. cass道路设计教程_(完整版)南方CASS7.1绘制道路断面图教程
  6. 计算机病毒制作教程,怎么制造一个小电脑病毒
  7. x550网卡linux驱动,Intel英特尔X520/X540/X550系列网卡驱动24.3版For Win8.1/10(2019年11月4日发布)...
  8. 计算机实验室安全员责任书,实验室安全目标责任书
  9. 关于SOME/IP的理解
  10. python 仿真 电力系统自动化_电力系统自动化仿真系统