Chinaunix首页 | 论坛 | 博客
  • 博客访问: 454954
  • 博文数量: 724
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5010
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(724)

文章存档

2011年(1)

2008年(723)

我的朋友

分类:

2008-10-13 16:56:36

共享内存封装类
作者:



本文介绍一个共享内存封装类,使共享内存的使用更简单化,特别适合更懒的程序员使用:-)

一、实现目标:简单化使用共享内存

二、使用说明

1. 创建共享内存CSFMServer对象, 需要为CSFMServer对象指定专用的名字,只要
系统中存在一个这样的对象,就可以在其他程序中简单方便地使用该共享内存。

CSFMServer(char *szFileName, char *szMapName, DWORD dwSize); 
Create(char *szFileName, char *szMapName, DWORD dwSize); 
参数1:NULL或指定的文件(将创建或打开并读写/麻烦)
参数2:要创建的共享内存对象名
参数3:要创建的共享内存对象大小

例如
m_SFMS.Create(NULL, "_ZZZ_OBJ_", 1);
2. 本地使用共享内存
使用 LPVOID GetBuffer() 返回共享内存地址,例如
char *p = (char*)m_SFMS.GetBuffer();
if (p)
	strcpy(p, "1234567890");
3. 创建共享内存CSFMClient对象,也需要为CSFMClient对象指定专用的名字(上一步使用的那个),即可使用共享内存。
CSFMClient(DWORD dwAccess, char *szMapName);
Open(DWORD dwAccess, char *szMapName);
参数1:共享内存对象访问方式(FILE_MAP_READ|FILE_MAP_WRITE)
参数2:共享内存对象名

例如:
CSFMClient *pCSFMC = new CSFMClient(FILE_MAP_READ, "_OBJ_ZZZ_");
4. 本地使用共享内存
使用 LPVOID GetBuffer() 返回共享内存地址,例如
char *p = (char*)pCSFMC->GetBuffer();
if (p) strcpy(p, "1234567890");

三、该类的具体实现代码如下:

//------------------------------------------------
// 2002/07/05
// awzzz
// SFMMem.h: interface for the CSFMServer class.
//------------------------------------------------
#if !defined(AFX_SFMSERVER_H__2D76A439_6388_4B07_AE7A_C82F458642ED__INCLUDED_)
#define AFX_SFMSERVER_H__2D76A439_6388_4B07_AE7A_C82F458642ED__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define	DEFAULT_FILENAME	NULL
#define	DEFAULT_MAPNAME		"_SFM_OBJ_"
#define	DEFAULT_MAPSIZE		(0xFFFF + 1)
// Shared FileMap Server
class CSFMServer  
{
public:
	CSFMServer();
	virtual ~CSFMServer();
	CSFMServer(char *szFileName, char *szMapName, DWORD dwSize);

protected:
	HANDLE	m_hFile;
	HANDLE	m_hFileMap;
	LPVOID	m_lpFileMapBuffer;

	char	*m_pFileName;
	char	*m_pMapName;
	DWORD	m_dwSize;

	int		m_iCreateFlag;

private:
	void _Init();
	void _Destory();

public:
	void Create(char *szFileName, char *szMapName, DWORD dwSize);
	LPVOID GetBuffer();
	DWORD GetSize();
};
// Shared FileMap Client
class CSFMClient  
{
public:
	CSFMClient();
	virtual ~CSFMClient();
	CSFMClient(DWORD dwAccess, char *szMapName);

protected:
	HANDLE	m_hFileMap;
	LPVOID	m_lpFileMapBuffer;

	char	*m_pMapName;

	int		m_iOpenFlag;

private:
	void _Init();
	void _Destory();

public:
	void Open(DWORD dwAccess, char *szMapName);
	LPVOID GetBuffer();
	DWORD GetSize();
};

#endif // !defined(AFX_SFMSERVER_H__2D76A439_6388_4B07_AE7A_C82F458642ED__INCLUDED_)
//------------------------------------------------------
// SFMMem.cpp: implementation of the CSFMServer class.
//------------------------------------------------------

#include "stdafx.h"
#include "SFMMem.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// Construction/Destruction

CSFMServer::CSFMServer()
{
	_Init();
	//
	Create(DEFAULT_FILENAME, DEFAULT_MAPNAME, DEFAULT_MAPSIZE);
}

CSFMServer::~CSFMServer()
{
	_Destory();
}

CSFMServer::CSFMServer(char *szFileName, char *szMapName, DWORD dwSize)
{
	_Init();
	//
	Create(szFileName, szMapName, dwSize);
}

void CSFMServer::_Init()
{
	m_hFile = NULL;
	m_hFileMap = NULL;
	m_lpFileMapBuffer = NULL;

	m_pFileName = NULL;
	m_pMapName = NULL;
	m_dwSize = 0;

	m_iCreateFlag = 0;
}

void CSFMServer::_Destory()
{
	if (m_lpFileMapBuffer)
	{
		UnmapViewOfFile(m_lpFileMapBuffer);
		m_lpFileMapBuffer = NULL;
	}
	
	if (m_hFileMap)
	{
		CloseHandle(m_hFileMap);
		m_hFileMap = NULL;
	}
	
	if (m_hFile && m_hFile != INVALID_HANDLE_VALUE)
	{
		CloseHandle(m_hFile);
		m_hFile = NULL;
	}

	if (m_pFileName)
	{
		free(m_pFileName);
		m_pFileName = NULL;
	}

	if (m_pMapName)
	{
		free(m_pMapName);
		m_pMapName = NULL;
	}

	_Init();
}

void CSFMServer::Create(char *szFileName, char *szMapName, DWORD dwSize)
{
	if (m_iCreateFlag)
		_Destory();

	if (szFileName)
		m_pFileName = _strdup(szFileName);
	//else m_pFileName = NULL;

	if (szMapName)
		m_pMapName = _strdup(szMapName);
	else m_pMapName = _strdup(DEFAULT_MAPNAME);

	if (dwSize > 0)
		m_dwSize = dwSize;
	else m_dwSize = DEFAULT_MAPSIZE;

	if (m_pFileName)
	{
		// file
		m_hFile = CreateFile(
			m_pFileName,
			GENERIC_READ|GENERIC_WRITE,
			FILE_SHARE_READ|FILE_SHARE_WRITE,
			NULL,
			OPEN_ALWAYS,//OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
			);
	}
	else
	{
		// system
		m_hFile = (HANDLE)0xFFFFFFFF;
	}

	if (m_hFile)
	{
		m_hFileMap = CreateFileMapping(
			m_hFile,
			NULL,
			PAGE_READWRITE,
			0,
			m_dwSize,
			m_pMapName
			);

		//使只有一个CSFMServer对象能操作内存对象
		//if (m_hFileMap != NULL && ERROR_ALREADY_EXISTS == GetLastError())
		//{
		//	CloseHandle(m_hFileMap);
		//	m_hFileMap = NULL;
		//}
	}

	if (m_hFileMap)
	{
		m_lpFileMapBuffer = MapViewOfFile(
			m_hFileMap,
			FILE_MAP_ALL_ACCESS,//FILE_MAP_WRITE|FILE_MAP_READ,
			0,
			0,
			m_dwSize
			);
	}

	m_iCreateFlag = 1;
}

LPVOID CSFMServer::GetBuffer()
{
	return (m_lpFileMapBuffer)?(m_lpFileMapBuffer):(NULL);
}

DWORD CSFMServer::GetSize()
{
	return m_dwSize;
}

// Construction/Destruction

CSFMClient::CSFMClient()
{
	_Init();
	//
	Open(FILE_MAP_READ, DEFAULT_MAPNAME);
}

CSFMClient::~CSFMClient()
{
	_Destory();
}

CSFMClient::CSFMClient(DWORD dwAccess, char *szMapName)
{
	_Init();
	//
	Open(dwAccess, szMapName);
}

void CSFMClient::Open(DWORD dwAccess, char *szMapName)
{
	if (m_iOpenFlag)
		_Destory();

	if (szMapName)
		m_pMapName = _strdup(szMapName);
	else m_pMapName = _strdup(DEFAULT_MAPNAME);

	m_hFileMap = OpenFileMapping(
		dwAccess,
		TRUE,
		m_pMapName
		);

	if (m_hFileMap)
	{
		m_lpFileMapBuffer = MapViewOfFile(
			m_hFileMap,
			dwAccess,
			0,
			0,
			0
			);
	}

	m_iOpenFlag = 1;
}

void CSFMClient::_Init()
{
	m_hFileMap = NULL;
	m_lpFileMapBuffer = NULL;

	m_pMapName = NULL;

	m_iOpenFlag = 0;
}

void CSFMClient::_Destory()
{
	if (m_lpFileMapBuffer)
	{
		UnmapViewOfFile(m_lpFileMapBuffer);
		m_lpFileMapBuffer = NULL;
	}
	
	if (m_hFileMap)
	{
		CloseHandle(m_hFileMap);
		m_hFileMap = NULL;
	}

	if (m_pMapName)
	{
		free(m_pMapName);
		m_pMapName = NULL;
	}

	_Init();
}

LPVOID CSFMClient::GetBuffer()
{
	return (m_lpFileMapBuffer)?(m_lpFileMapBuffer):(NULL);
}

DWORD CSFMClient::GetSize()
{
	// unnable use
	return 0;
}
测试环境:Win2K+VC6+普通应用程序
未对服务程序/ISAPI等其他应用进行测试,应该也是可以的

--------------------next---------------------

你的电脑好落啊
( softhero 发表于 2004-10-20 9:41:00)
 
sos!!!此方案在WinNT下无效!!!!!!程序执行是没有问题的,但是,请注意听你那可怜的硬盘,正在痛苦地呻吟。。。。。。|WinNT实实在在将这倒霉的内存映射文件当成文件来处理了。。。。。。也就是说,和你打开一个可共享的文件,然后同时几个进程操作毫无区别。。。。 ( wordstar 发表于 2003-9-25 1:17:00)
 
awzzz:对服务程序测试成功有效
(发表于2002-7-15 8:34:00)
可是我在ISAPI程序里使用是无效的,要修改CreatFile和CreatFileMapping的安全描述符才可以用的。 ( summuer 发表于 2003-8-13 14:21:00)
 
没有同步保护阿! ( fallwind 发表于 2003-1-14 11:40:00)
 
补充说明:

void CShareMemDlg::OnButton2() 
{
// TODO: Add your control notification handler code here

CSFMClient *pCSFMC = new CSFMClient(FILE_MAP_READ, "_OBJ_ZZZ_");
char *p = (char*)pCSFMC->GetBuffer();
if (p) strcpy(p, "1234567890");
delete pCSFMC;//释放
}

以下行
if (p) strcpy(p, "1234567890");
是为了测试出错情况

因为
CSFMClient *pCSFMC = new CSFMClient(FILE_MAP_READ, "_OBJ_ZZZ_");
FILE_MAP_READ只能读,不能写,写为|FILE_MAP_WRITE

当时没写注释,自己现在都晕了 ( awzzz 发表于 2002-9-6 17:00:00)
 
呵呵!我差点忘了,共享内存由操作系统管理和分配,用户只能申请使用权...... ( Micro 发表于 2002-7-27 13:48:00)
 
Micro老哥,当没有其他用户使用时共享内存时,共享内存变会真正释放的。 ( tdy 发表于 2002-7-21 8:28:00)
 
据我所知,使用共享内存的一个实例应该没有权限直接释放共享内存.因为其他例程可能正在使用.我们是不是应该使用象COM组件的方法,为每一块共享内存设一标识位,内存的每次实例化使该标识加1,用完后减1,而当该标识为0时,则彻底释放该共享内存....:) ( Micro 发表于 2002-7-16 11:31:00)
 
对服务程序测试成功有效 ( awzzz 发表于 2002-7-15 8:34:00)
 
懒好! ( VC70新手 发表于 2002-7-14 19:46:00)
 
.......................................................

--------------------next---------------------

阅读(386) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~