专业购物网站免费网站在线观看
内存映射文件概念:
通过内存映射文件函数,可以将磁盘上的文件的全部或部分映射到进程的虚拟地址空间的某个位置,一旦完成了映射,就可以通过指针像访问内存一样访问磁盘文件。读取文件和写入文件的操作都是直接对内存进行操作。
通过内存映射文件,能够更高效率地读取文件,提高系统性能。
内存映射文件的实现原理:

实际上映射这个步骤就只有过程一了,映射完成后我们会得到一个地址,这个过程不存在数据拷贝。然后我们可以通过这个地址来像访问内存一样访问文件。但其实这个时候还不算真正完成了整个操作。在我们第一次对数据进行访问的时候,因为我们并没将数据拷贝到内存,所以会引发一个缺页中断,就是过程3,然后系统会将硬盘上的文件拷贝到内存中。当然并不会一次将文件全部的数据拷贝到内存中,一般是我们需要用哪些数据的时候拷贝哪些数据,并且数据是以4KB大小的页为单位的。
更详细的解释可以看看这个博客:https://blog.csdn.net/mg0832058/article/details/5890688
除了用于加载文件,内存映射文件也可以在同一台计算机上运行的多个进程之间共享数据,实现原理很简单,只要将不同的进程的间的共享数据页提交到虚拟内存的相同页面就可以了。这样,当一个进程改变了数据页的内容,通过分页映射机制,其他进程的共享数据区的内容就会发生改变,因为它们实际在同一个地方。
使用内存映射文件:
CreateFileMapping:
invoke    CreateFileMapping,hFile,lpFileMappingAttributes,\flProtect,dwMaximumSizeHigh,dwMaximumSizeLow,lpName
.if       eaxmov    hFileMap,eax
.endif 
该函数创建一个内存映射文件对象,这个步骤决定了是在磁盘文件中建立建立内存映射文件,还是在页文件中建立进程间的共享映射。
函数的第一个参数是我们要建立内存映射的文件的句柄,也就是说我们得先打开一个文件得到它的句柄。如果是要建立一个位于页文件中的内存映射文件供不同进程共享,那么这个参数指定为1。
第二个参数指向一个SECURITY_ATTRIBUTES结构,它用来定义内存映射文件对象是否可继承,不需要继承的话就把这个参数设置为-1。
第三个参数指定该内存映射我呢见的保护类型,它可以是下面取值:
- PAGE_READONLY:内存映射文件提交的内存页面为只读属性
 - PAGE_READWRITE: 内存映射文件提交的内存是可读写的。
 - PAGE_WRITECOPY:内存映射文件提交的内存可以有Copy on Write属性。
 
dwMaximumSizeHigh和dwMaximumSizeLow参数组合指定了一个64位的内存映射文件的长度。如果这个长度大于磁盘文件的长度,那么磁盘文件将被扩展到这个长度,如果小于就只能取磁盘文件的一部分。如果设置为0,那么内存映射文件的大小就会被自动扩展到磁盘文件的大小。
最后那个参数指定一个字符串,是用来给定内存映射文件的名字的。如果是用于进程间的共享内存,那么这个名字就很有必要了,因为其他进程建立映射的时候要用到这个名字。如果只是用于磁盘文件,那这个就没有必要了。
OpenFileMapping:
invoke    OpenFileMapping,dwDesiredAccess,bInheritHandle,lpName
.if       eaxmov    hFileMap,eax
.endif 
该函数打开一个创建好的对象。最后一个参数就是之前的CreateFileMapping函数创建的内存映射文件的对象的名字。然后第一个参数指定保护类型:
- FILE_MAP_WRITE:可写属性
 - FILE_MAP_READ:可读属性
 - FILE_MAP_COPY:Copy on Write属性
 
MapViewOfFile:
invoke    MapViewOfFile,hFileMap,dwDesiredAccess,\dwFileOffsetHigh,dwFileOffsetLow,dwNumberOfBytesToMap
.if       eaxmov    lpMemory,eax
.endif 
该函数用来映射内存映射文件的一个视图。我们之前创建或打开了一个内存映射文件对象后还不算完,我们还得通过这个函数在进程的地址空间中映射那个文件的视图,该操作就是给需要映射的文件内容分配线性地址空间,并将线性地址和文件内容对应起来。当一个视图被映射的时候,系统只是为它分配足以覆盖文件视图的连续地址空间,并不马上将它提交到物理存储器的文件中,只有第一次读取内存页面的时候,系统才分配一个对应于视图页面的物理内存页面。
第一个参数就是内存映射文件函数对象句柄,后面一个参数也是指定保护类型,属性气质==取值和上一个函数一样。
参数dwFileOffsetHigh和参数dwFileOffsetLow组成一个64位的偏移,指出从视图的基地址从文件的哪个位置开始映射。最后一个参数指定要映射的字节数,指定为0的话就是整个文件,同时偏移地址被忽略。如果映射成功,函数返回一个指向文件开始位置的指针。然后我们就可以通过这个指针来访问文件了。
UnmapViewOfFile:
invoke    UnmapViewOfFile,lpMemory 
该函数解除映射。
CloseHandle:
invoke    CloseHandle,hFileMap 
该函数关闭内存映射文件对象句柄。
FlushViewOfFile:
invoke    FlushViewOfFile,lpMemory,dwFileSize 
该函数将从指定地址开始,指定大小的数据块中的脏页面写到磁盘。
当对视图中的内存进行修改后,系统会在视图撤销映射或映射对象被删除时自动将数据写到磁盘中。但是程序也可以用上面这个函数手动写入。
根据以上,我们可以写一个共享内存的小程序。
- 用OpenFileMapping函数打开一个命名的内存映射文件对象,得到内存映射文件对象句柄,如果打开成功则跳到3,不成功则跳到2.
 - 用CreateFileMapping函数创建一个命名的内存映射文件对象,得到内存映射文件对象句柄。
 - 用MapViewOfFile函数映射对象的一个视图,得到指向映射到内存的第一个字节的指针lpMemory。
 - 用这个指针来对共享内存进行操作。
 - UnmapViewOfFile解除视图映射。
 - CloseHandle关闭内存映射文件。
 
因为这个是共享内存,所以没有打开文件那一步。下面是程序的资源脚本文件:
#include	<resource.h>
#define		ICO_MAIN	0x1000
#define		DLG_MAIN	0x100
#define		IDC_TXT		0x101
#define		IDC_INFO	0x102ICO_MAIN	ICON		"Main.ico"
DLG_MAIN	DIALOG	229,208,211,55
STYLE	DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION	"内存映射文件共享"
FONT	9  , "宋体"
BEGINLTEXT	"请执行本程序的多个拷贝,并尝试在下面输入文本:",-1,7,8,196,8EDITTEXT	IDC_TXT,7,22,197,12,ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOPLTEXT	"",IDC_INFO,8,41,196,8
END 
然后是程序的汇编源代码:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;当打开第一个文件,程序创建共享内存映射文件,映射文件。打开第二个文件,打开共享内存映射文件对象,映射文件,
;映射文件后可以直接通过函数返回的指针像访问内存一样访问函数,而写入内存的数据会在
;当在某一个文件输入框输入字符,程序检测字符,设置共享内存内数据为输入框内容,每个进程的函数的计时器
;都发射消息,将共享内存映射文件中的数据放入对话框中显示。
;当有进程结束,进程释放句柄,解除视图映射,并不用担心其他进程会收到影响,因为WINDOWS中有计数器,每当开启一个进程
;计数器加一,结束一个进程计数器减一,所以只有当进程全部结束系统才会释放内存映射文件
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.386.model flat,stdcalloption casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Include文件
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc 
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Equ
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN	equ		1000h
DLG_MAIN	equ		100h
IDC_TXT		equ		101h
IDC_INFO	equ		102h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.data?
hInstance		dd		?
hWinMain		dd		?
hFileMap		dd		?
lpMemory		dd		?.const
szErr			db		'无法建立内存共享文件',0
szMMFName		db		'MMF_Share_Example',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CreateMMF		procinvoke		OpenFileMapping,FILE_MAP_READ or FILE_MAP_WRITE,\		;打开内存映射文件对象,返回内存映射文件句柄0,addr szMMFName.if			! eaxinvoke	CreateFileMapping,-1,NULL,PAGE_READWRITE,0,\	;如果之前没有创建对象,则创建一个4096,addr szMMFName.if		! eaxjmp		@F.endif.endifmov			hFileMap,eaxinvoke		MapViewOfFile,eax,FILE_MAP_READ or FILE_MAP_WRITE,\		;映射整个文件,返回内存地址0,0,0.if			eaxmov		lpMemory,eax;mov		dword ptr [eax],0ret.endifinvoke		CloseHandle,hFileMap
@@:invoke		MessageBox,hWinMain,addr szErr,NULL,MB_OKinvoke		EndDialog,hWinMain,FALSEret_CreateMMF		endp_CloseMMF		procinvoke		UnmapViewOfFile,lpMemory								;解除视图映射invoke		CloseHandle,hFileMap									;关闭句柄mov			lpMemory,0mov			hFileMap,0ret
_CloseMMF		endp_ProcDlgMain	proc		uses ebx edi esi hWnd,wMsg,wParam,lParamlocal		@szBuffer[4096]:bytemov			eax,wMsg.if			eax == WM_TIMERinvoke	SetDlgItemText,hWnd,IDC_INFO,lpMemory.elseif		eax == WM_CLOSEinvoke	KillTimer,hWnd,1invoke	_CloseMMFinvoke	EndDialog,hWinMain,0.elseif		eax == WM_INITDIALOGpush	hWndpop		hWinMaininvoke	LoadIcon,hInstance,ICO_MAINinvoke	SendMessage,hWnd,WM_SETICON,ICON_BIG,eaxinvoke	SendDlgItemMessage,hWnd,IDC_TXT,\EM_SETLIMITTEXT,100,0invoke	_CreateMMFinvoke	SetTimer,hWnd,1,100,NULL;设置一个计时器.elseif		eax == WM_COMMANDmov		eax,wParam.if		ax == IDC_TXT && [lpMemory]					;如果输入栏有变化invoke	GetDlgItemText,hWnd,IDC_TXT,\		;获取输入栏内容,存入共享内存映射文件lpMemory,4096.endif.elsemov		eax,FALSEret.endifmov			eax,TRUEret
_ProcDlgMain	endpstart:invoke		GetModuleHandle,NULLmov			hInstance,eaxinvoke		DialogBoxParam,hInstance,DLG_MAIN,NULL,\offset _ProcDlgMain,NULLinvoke		ExitProcess,NULL
end		start 

在一个窗口输入,其他窗口都会跟着变化。
