使用内存映射文件在进程间共享数据

说道内存映射文件,我感觉好多人都对此不是很理解(我也是其中一个。。。),经过不断地学习,我自己对此也有一点小小的理解,(也可以细看我转发的一篇博文,图文并茂,我深受启发http://blog.csdn.net/qq_22642239/article/details/51496988)

使用内存映射文件首先应该创建一个内存映射文件的对象(也就是在你需要映射的文件上建立的一个对象)使用CreateFileMapping函数创建,函数返回一个内存映射文件对象的句柄(假如是hFileMap)。

创建过内存映射文件的对象之后,就应该使用MapViewOfFile函数创建内存映射文件的一个视图,创建成功,函数会返回一个地址,存取这个地址指定的内存块就相当于存取文件的内容了(具体细节可以看一下详细介绍内存映射文件那篇博文),这就是内存映射文件的使用方法。

本次程序编写介绍的的是使用内存映射文件在进程间共享数据(说的通俗点就是运行几个程序,程序对应相应的进程,建立一个内存映射文件共享区域,使每个进程都能利用这个区域的数据,程序中则是在每个进程对应的程序中显示出这个内存共享区域的数据,每个进程也可以在这个区域中写入数据),从一个程序中输入数据,可以在另一个程序中看到这个输入的数据。具体情况如下图:


我在第一个程序的文本编辑控件中输入111111111   在另外两个程序中也能读取到这个111111111,然后在下面那个静态文本框中显示出来。


下面来看一下程序的实现框架:

资源文件
图标IDI_ICON1
对话框IDD_DIALOG1
编辑文本框IDC_TXT
静态文本框1IDC_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


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值