使用内存映射文件在进程间共享数据
说道内存映射文件,我感觉好多人都对此不是很理解(我也是其中一个。。。),经过不断地学习,我自己对此也有一点小小的理解,(也可以细看我转发的一篇博文,图文并茂,我深受启发http://blog.csdn.net/qq_22642239/article/details/51496988)
使用内存映射文件首先应该创建一个内存映射文件的对象(也就是在你需要映射的文件上建立的一个对象)使用CreateFileMapping函数创建,函数返回一个内存映射文件对象的句柄(假如是hFileMap)。
创建过内存映射文件的对象之后,就应该使用MapViewOfFile函数创建内存映射文件的一个视图,创建成功,函数会返回一个地址,存取这个地址指定的内存块就相当于存取文件的内容了(具体细节可以看一下详细介绍内存映射文件那篇博文),这就是内存映射文件的使用方法。
本次程序编写介绍的的是使用内存映射文件在进程间共享数据(说的通俗点就是运行几个程序,程序对应相应的进程,建立一个内存映射文件共享区域,使每个进程都能利用这个区域的数据,程序中则是在每个进程对应的程序中显示出这个内存共享区域的数据,每个进程也可以在这个区域中写入数据),从一个程序中输入数据,可以在另一个程序中看到这个输入的数据。具体情况如下图:
我在第一个程序的文本编辑控件中输入111111111 在另外两个程序中也能读取到这个111111111,然后在下面那个静态文本框中显示出来。
下面来看一下程序的实现框架:
图标 | IDI_ICON1 |
对话框 | IDD_DIALOG1 |
编辑文本框 | IDC_TXT |
静态文本框1 | IDC_INFO 显示内存共享区域的数据 |
静态文本框2 | 显示提示字符 |
建立内存共享文件 | _CreateMMF() |
解除视图映射,关闭内存映射文件 | _CloseMMF() |
对话框消息处理过程 | _ProcDlgMain() |
程序入口,创建模态对话框 | start: DialogBoxParam() |
首先来看一下资源文件,自己调整好对话框的大小,根据自己的习惯定义对话框的对话框的风格就可以了,这次依然使用的是ResEdit资源编写工具,详细代码如下:
// Generated by ResEdit 1.6.6
// Copyright (C) 2006-2015
// http://www.resedit.net
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 0, 0, 223, 95
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_GROUP | WS_TABSTOP | WS_POPUP | WS_THICKFRAME | WS_SYSMENU
CAPTION "内存映射文件共享"
FONT 8, "Ms Shell Dlg"
{
LTEXT "", IDC_INFO, 11, 71, 192, 14, SS_LEFT, WS_EX_LEFT
LTEXT "请执行本程序的多个拷贝,并尝试在下面输入文本:", 0, 13, 13, 185, 9, SS_LEFT, WS_EX_LEFT
EDITTEXT IDC_TXT, 12, 36, 190, 20, ES_AUTOHSCROLL, WS_EX_LEFT
}
//
// Icon resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_ICON1 ICON ".\\icon2.ico"
下面来看一下源代码部分的问题:
首先在创建内存映射文件共享区域的时候,创建了内存映射文件的对象的,以及映射了对象的视图得到指向映射到内存的第一个字节的指针,当不再使用它们的时候,需要手动把它们都处理掉(需要我们自己动手处理。。。)。
还有一个就是以前遇到过的标号问题,这次写的时候居然都忘记了,在这里从新总结一下:
@@ ;标号
@F ;表示匹配本条指令后的第一个@@标号
@B ; 表示匹配本条指令前的第一个@@标号
这个标号只在MASM中有效
下面来看一下程序源代码,注意注释的地方:
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
IDD_DIALOG1 equ 100
IDI_ICON1 equ 101
IDC_TXT equ 40000
IDC_INFO equ 40001
.data?
hInstance dd ?
hWinMain dd ?
hFileMap dd ?
lpMemory dd ?
.const
szErr db '无法建立内存共将文件',0
szMMFName db 'MMF_Share_Example',0
.code
_CreateMMF proc
invoke OpenFileMapping,FILE_MAP_READ or FILE_MAP_WRITE,0,addr szMMFName
.if ! eax
invoke CreateFileMapping,-1,NULL,PAGE_READWRITE,0,4096,addr szMMFName ; 4096表示的是一个页的大小, win32内存分页机制中一个页的大小 为4kb
.if ! eax
jmp @F
.endif
.endif
mov hFileMap,eax
invoke MapViewOfFile,eax,FILE_MAP_READ or FILE_MAP_WRITE,0,0,0
.if eax
mov lpMemory,eax
mov dword ptr [eax],0
ret
.endif
invoke CloseHandle,hFileMap
@@:
invoke MessageBox,hWinMain,addr szErr,NULL,MB_OK
invoke EndDialog,hWinMain,-1
ret
_CreateMMF endp
_CloseMMF proc
invoke UnmapViewOfFile,lpMemory
invoke CloseHandle,hFileMap
mov lpMemory,0
mov hFileMap,0
ret
_CloseMMF endp
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
LOCAL @szBuffer[4096]:byte
mov eax,wMsg
.if eax == WM_TIMER
invoke SetDlgItemText,hWnd,IDC_INFO,lpMemory
.elseif eax == WM_CLOSE
invoke KillTimer,hWnd,1
invoke _CloseMMF
invoke EndDialog,hWinMain,0
.elseif eax == WM_INITDIALOG
push hWnd
pop hWinMain
invoke LoadIcon,hInstance,IDI_ICON1
invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
invoke SendDlgItemMessage,hWnd,IDC_TXT,EM_SETLIMITTEXT,100,0
invoke _CreateMMF
invoke SetTimer,hWnd,1,200,NULL
.elseif eax == WM_COMMAND
mov eax,wParam
.if ax == IDC_TXT && lpMemory
invoke GetDlgItemText,hWnd,IDC_TXT,lpMemory,4096
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
end start
下面来看一下本程序中的几个API函数:
OpenFileMapping()
功能:
打开一个现成的文件映射对象的函数
声明:
HANDLE WINAPI OpenFileMapping(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ LPCTSTR lpName
);
参数:
lpName:指向的名字就是创建对象时使用的名字
dwDesiredAccess:指定保护类型,他可以是以下的取值:
FILE_MAP_WRITE(或FILE_MAP_ALL_ACCESS)-----------可写属性
FILE_MAP_READ--------可读属性
FILE_MAP_COPY-----------Copy on write属性
返回值:
打开的内存映射文件对象的句柄
CreateFileMapping()
功能:
创建一个新的文件映射内核对象。
参数原型:
HANDLE CreateFileMapping(
HANDLE hFile, //物理文件句柄
LPSECURITY_ATTRIBUTES lpAttributes, //安全设置
DWORD flProtect, //保护设置
DWORD dwMaximumSizeHigh, //高位文件大小
DWORD dwMaximumSizeLow, //低位文件大小
LPCTSTR lpName //共享内存名称
);
返回值:
Long,新建文件映射对象的句柄;零意味着出错。会设置GetLastError。即使函数成功,但倘若返回的句柄属于一个现成的文件映射对象,那么GetLastError也会设置成ERROR_ALREADY_EXISTS。在这种情况下,文件映射的长度就是现有对象的长度,而不是这个函数指定的尺寸。
MapViewOfFile()
功能:
将一个文件映射对象映射到当前应用程序的地址空间。MapViewOfFileEx允许我们指
定一个基本地址来进行映射。
原型:
LPVOID WINAPI MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
参数:
hFileMappingObject Long,文件映射对象的句柄。
dwDesiredAccess Long,下述常数之一:
FILE_MAP_WRITE 映射可读可写。文件映射对象必须通过PAGE_READWRITE访问创建。
FILE_MAP_READ 映射只读。文件映射对象必须通过PAGE_READ 或 PAGE_READWRITE访问创建。
FILE_MAP_ALL_ACCESS 与FILE_MAP_WRITE相同。
FILE_MAP_COPY 映射时保留写操作的副本。文件映射对象必须用PAGE_WRITECOPY访问在win95下创建
dwFileOffsetHigh Long,文件中映射起点的高32位地址。
dwFileOffsetLow Long,文件中映射起点的低32位地址。
dwNumberOfBytesToMap Long,文件中要映射的字节数。用零映射整个文件映射对象。
lpBaseAddress Long,指定映射文件映射对象的地址。如这个地址处没有足够的内存空间,那么对MapViewOfFileEx的调用会失效。零表示允许windows寻找一个地址。
返回值:
如果成功,则返回映射视图文件的开始地址值。
如果失败,则返回 NULL.可调用GetLastError()查看错误。
UnmapViewOfFile()
功能:
是停止当前程序的一个内存映射
原型:
Declare Function UnmapViewOfFile& Lib "kernel32" (ByVal lpBaseAddress As Long)
参数:
lpBaseAddress Long,指定要解除映射的一个文件映射的基准地址。这个地址是早先用MapViewOfFile函数获得的
返回值:
Long,非零表示成功,零表示失败。会设置GetLastError。
使用内存映射文件在进程间共享数据相关推荐
- 使用内存映射文件在进程之间共享数据
数据共享方法是通过让两个或多个进程映射同一个文件映射对象的视图来实现的,这意味着它们将共享物理存储器的同一个页面.因此,当一个进程将数据写入一个共享文件映射对象的视图时,其他进程可以立即看到它们视图中 ...
- c++ 内存映射文件进程间共享数据
int main(int argc, char *argv[]) { //RecursiveDelete("C:\\20_128\\"); //Self ...
- 数据共享,内存映射文件和虚拟内存,共享内存
一.内存映射 内存映射文件允许开发人员预定一块地址空间区域并给区域调拨物理存储器.内存映射文件的物理存储器来自磁盘已有的文件,而不是来自系统的页交换文件.一旦把文件映射到地址空间,就可以对它进行访问, ...
- windows核心编程之进程间共享数据
有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存 ...
- 如何在进程间共享数据
1.引言 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换,就如同 ...
- VC 利用DLL共享区间在进程间共享数据及进程间广播消息
在进程间共享数据有很多种方法,剪贴板,映射文件等都可以实现,这里介绍用 DLL 的共享区间在进程间共享数据,及共享数据有变化时及时的反馈给各相关进程. 一.在DLL中设置共享区间 在DLL中是用数据段 ...
- python 多进程共享变量manager_python 进程间共享数据 multiprocessing 通信问题 — Manager...
Python中进程间共享数据,处理基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Mana ...
- python进程间共享数据_python 进程间共享数据 (二)
Python中进程间共享数据,除了基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Mana ...
- DLL入门浅析(5)——使用DLL在进程间共享数据
在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的,因为所有的进程用的都收同一块地址空间:而在Win32环境中,情况却发生了变化,每个进程都有了它自己的地址空间,DLL函数中的代码所 ...
- 进程锁、事件、进程队列、进程间共享数据、生产者消费者模型
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 进程锁(Lock) 锁的基本概念 锁的基本用法 模拟12306抢票软件 信号量:Semaphone 概念 Semaphore ...
最新文章
- boost::hana::greater_equal用法的测试程序
- 【OOP】零钱通项目
- 隔行变色java代码_jquery入门—选择器实现隔行变色实例代码
- python条件语句有哪些_Python 条件语句
- Rust 1.34.0 发布
- 6、easyUI-拖放事件及应用
- 台式计算机打字标准手法,电脑打字技巧口诀
- 清理C盘空间,给Win7释放更多C盘容量
- 啊哈添柴挑战Java1491. 奔跑的小人
- 免费使用短信服务接口 ----用Java实现
- 【AI视野·今日CV 计算机视觉论文速览 第167期】Mon, 11 Nov 2019
- [算法设计与分析] 用动态规划法求解资源分配问题 (Java)
- 黑盒测试——因果图法
- 如何将Excel一页转PDF变多页?好用的PDF转换工具推荐
- 公开课分享《如何快速有效地编写一份商业计划书》
- spark graphx实现共同好友的聚合
- C#串口通讯+BigEndian+Little-Endian(大端和小端方案)
- Jam的计数法--Java
- LeetCode60. 第k个排列
- 自定义微博小尾巴(源码+解析)
热门文章
- 算术编码python实现_算术编码(Arithmetic coding)的实现
- 详细关闭iiop方法_安卓手机卡顿清理垃圾是没用的,教你关闭几个设置,告别手机迟钝...
- mysql 前缀索引_MySQL前缀索引
- java 子线程传参_java开启新线程并传参的两种方法
- cookie被淘汰_可爱可恨的 Cookie
- Solaris 11中的变化
- day15 ( 集合框架)
- jenkins-启动和关闭服务
- 单元测试新方法:用setUp方法 @Before注释
- php 中的全局变量的理解