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

Windows提供了多种机制允许进程之间能够共享数据。比如,WM_COPYDATA消息,剪贴板,邮件槽(mailslot),管道(pipe),套接字(socket)等。在同一台机器上共享数据最底层的机制就是内存映射文件。

使用内存映射文件的步骤如下:

1.       创建或打开一个文件内核对象,该对象标识了要用作内存映射文件的那个磁盘文件(CreateFile)

2.       创建一个文件映射内核对象(CreateFileMapping)

3.       告诉系统把文件映射对象的部分或全部映射到进程的地址空间中(MapViewOfFile)

调用CreateFile是为了告诉操作系统文件映射的物理存储器所在的位置。为了告诉系统文件映射对象需要多大的物理存储器,须调用CreateFileMapping。在创建了文件映射对象之后,还需要使用MapViewOfFile来将文件的数据映射到进程的地址空间中。当我们把一个文件映射到地址空间中的时候,不必一下子映射整个文件,可以每次只把一小部分映射到地址空间中。文件中被映射到进程地址空间中的部分被称为视图(View)。

用完内存映射文件之后,须执行以下步骤来做清理工作:

1.       告诉系统取消从进程地址空间对文件映射对象的映射(UnmapViewOfFile)

2.       关闭文件映射内核对象(CloseHandle)

3.       关闭文件内核对象(CloseHandle)

不再需要把文件的数据映射到进程的地址空间时,需要调用UnmapViewOfFile来释放内存区域。如果不这样做,在进程终止之前,区域将得不到释放。

无论以什么方式创建的内核对象,我们都要调用CloseHandle向系统表明我们已经结束使用对象,否则会在进程继续运行的过程中引起资源泄漏。

如果我们希望创建的文件映射的物理存储器不是磁盘上的文件,而是从页交换文件中调拨物理存储器,则只需要调用CreateFileMapping,并将INVALID_HANDLE_VALUE作用hFile参数传入。

当我们创建了文件映射对象,对将其映射到进程地址空间中,我们就可以像使用任何内存区域一样使用它了。如果想要在其他进程共享数据,那么可以在调用CreateFileMapping时指定pszName该文件映射对象的名称。这样,其他进程就可以以该名称来调用CreateFileMapping或者OpenFileMapping,并使用该文件映射对象的数据了。

例子

第一个进程

该进程首先调用CreateFileMapping创建文件映射对象,可以看到传入了INVALID_HANDLE_VALUE参数,这表明该文件映射对象从页交换文件中调拨物理存储器。另外,该文件映射对象命名为“Global\\MyFileMappingObject”。

接着,调用MapViewOfFile创建文件映射对象的视图,并将其返回值赋给pBuf,再调用CopyMemory函数将一个字符串写到该视图中去以让其他进程访问。

当进程不再需要使用文件映射对象,需要调用CloseHandle关闭其句柄。

#include <windows.h>
#include <conio.h>
#include "stdafx.h"

#define BUF_SIZE 256
TCHAR sName[] = _T("Global\\MyFileMappingObject");
TCHAR sNick[] = _T("Message from process 1!");


int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hMapFile;
	LPCTSTR pBuf;

	hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, 
		NULL, PAGE_READWRITE, 0, BUF_SIZE, sName);
	if (hMapFile == NULL) {
		_tprintf(TEXT("Could not create file mapping object (%d).\n"), GetLastError());
		return 1;
	}

	pBuf = (LPCTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
	if (pBuf == NULL) {
		_tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError());
		CloseHandle(hMapFile);

		return 1;
	}

	CopyMemory((PVOID)pBuf, sNick, (_tcslen(sNick) * sizeof(TCHAR)));
	_getch();
	
	UnmapViewOfFile(pBuf);

	CloseHandle(hMapFile);

	return 0;
}

第二个进程

第二个进程首先调用OpenFileMapping函数开打开命名为“Global\\MyFileMappingObject”的文件映射对象。然后调用MapViewOfFile来获得视图的指针,pBuf。获得该指针后,便可以像使用一般的字符串一要来操作该字符串,调用MessgeBox可以显示该来自进程1的字符串。

#include <windows.h>
#include "stdafx.h"

#define BUF_SIZE 256
TCHAR szName[]= _T("Global\\MyFileMappingObject");

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hMapFile;
	LPCTSTR pBuf;

	hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, szName);

	if (hMapFile == NULL) {
		_tprintf(TEXT("Could not open file mapping object (%d).\n"),  GetLastError());

		return 1;
	}


	pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, BUF_SIZE);
	if (pBuf == NULL) {
		_tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError());
		CloseHandle(hMapFile);

		return 1;
	}

	MessageBox(NULL, pBuf, _T("Process2"), MB_OK);

	UnmapViewOfFile(pBuf);
	
	CloseHandle(hMapFile);

	return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值