// filemapping.h: interface for the UC_FILEMAPPING class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_)
#define AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////
// 模块: 内存映射文件用户类
// 作者: 张旻
// 创建: 2002.01.16
// 说明:
// 利用内存映射文件进行进程之间的内存共享,
// 目前的32位应用程序寻址范围4GB, 不需要高位
//////////////////////////////////////////////////
//#include "uc_log.h"
#include "windows.h"
#include <stdlib.h>
//自定义返回值
//RET_BADARG 参数非法 ret bad arg
#define RET_USER 0
#define RET_FILEOPENNED RET_USER + 1 //文件已经打开 file openned
#define RET_FILENOTOPENNED RET_USER + 2 //文件未打开 file not openned
#define RET_BUFFERTOOBIG RET_USER + 3 //缓冲区过大 buffer too big
#define RET_BUFFEROVERFLOW RET_USER + 4 //缓冲区溢出 buffer over flow
#define RET_FILEPROCESSING RET_USER + 5 //文件正在操作 file processing
#define RET_OFFSETOVERFLOW RET_USER + 6 //偏移量溢出 off set overflow
#define RET_BADARG RET_USER + 7 //参数非法 ret bad arg=未定义
#define RET_FILEERR RET_USER + 8 //文件操作失败 file err=未定义
#define RET_OK RET_USER + 9 //操作成功 ok=未定义
//共享内存的预留长度信息结构预定义
typedef struct tagMapInfo
{
DWORD dwSizeHigh; //高位文件大小
DWORD dwSizeLow; //低位文件大小
char szMappingName[_MAX_PATH]; //映射名称
int count; //用来计述有多少个文件映射对象打开了同一个文件
//tagMapInfo()
//{
// dwSizeHigh = dwSizeLow = 0;
// memset( szMappingName, 0, _MAX_PATH );
//}
} US_MAPINFO, * PUS_MAPINFO;
//分页门限
#define HIGH_MAX 0xFFFFFFFE //高位最大值 high max
#define LOW_MAX 0xFFFFFFFF - sizeof(US_MAPINFO) //低位最大值 low max
#define INFO_LEN sizeof(US_MAPINFO) //头信息长度 info len
#define NOPHYSICALFILE 0xFFFFFFFF //不需要物理文件 no physical file
class FileMapping //: public UC_LOG //uc file mapping
{
public:
DWORD GetSize();
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 写入映射文件
// 参数:
// [in] lpBuf 缓冲区
// [in] nSize 缓冲区大小
// [in] dwOffsetLow 偏移地址地位
// 修改 [in] isAppend=TRUE 如果isAppend为TRUE直接加到映射文件的尾部,参数dwOffsetLow表示的偏移地址不起作用
// 返回:
// RET_BADARG 参数非法 ret bad arg
// RET_BUFFERTOBIG 缓存区过大 ret buffer to big
// RET_BUFFEROVERFLOW 缓冲区溢出 ret buffer overflow
// RET_FILENOTOPENNED 文件未打开 file not openned
// RET_FILEPROCESSING 文件正在操作 file processing
// RET_FILEERR 文件操作失败 file err
// RET_OK 操作成功 ok
//////////////////////////////////////////////////
DWORD Write( LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow=0, BOOL isAppend=TRUE );
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 读取映射文件
// 参数:
// [in] lpBuf 缓冲区
// [in] nSize 缓冲区大小
// [in] dwOffsetLow 偏移地址地位
// 返回:
// RET_BADARG 参数非法
// RET_BUFFERTOBIG 缓存区过大
// RET_BUFFEROVERFLOW 缓冲区溢出
// RET_FILENOTOPENNED 文件未打开
// RET_FILEPROCESSING 文件正在操作
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD Read( LPVOID lpszBuf, UINT &nSize, DWORD dwOffsetLow=0 );
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 关闭映射文件
// 参数:
// [in] wantDump 需要导出
// 返回:
// RET_FILENOTOPENNED 文件未打开
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD Close( BOOL wantDump=TRUE );
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 打开映射文件
// 参数:
// [in] lpszMappingName 映射内存命名
// 返回:
// RET_BADARG 参数非法
// RET_FILEOPENNED 文件已经打开
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD Open( LPCTSTR lpszMappingName );
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 打开映射文件
// 参数:
// [in] lpszFilePath 物理文件路径
// [in] lpszMappingName 映射内存命名
// [in] dwSizeLow 低位空间大小
// 返回:
// RET_BADARG 参数非法
// RET_FILEOPENNED 文件已经打开
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD Open( LPCTSTR lpszFilePath, LPCTSTR lpszMappingName, DWORD dwSizeLow=0 );
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 构造函数
//////////////////////////////////////////////////
FileMapping();
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 析构函数
//////////////////////////////////////////////////
virtual ~FileMapping();
LPVOID getlpAddress()
{
return m_lpAddress;
}
protected:
HANDLE m_hPhysicsFile; //物理文件句柄
HANDLE m_hMappingFile; //映射文件句柄
HANDLE m_hFileOP; //文件操作互斥量
HANDLE m_hMutex;
LPVOID m_lpCursor; //映射游标地址指针
LPVOID m_lpAddress; //映射文件地址指针
PUS_MAPINFO m_pusMapInfo; //映射内存头信息
BOOL m_isFileLoaded; //工作状态标志
BOOL m_isMyHandle; //是否是自己创建的文件映射
DWORD m_dwSysAlloc; //系统分配内存的最小单位
private:
int count; //用来计述有多少个文件映射对象打开了同一个文件
DWORD FlushView();
DWORD GetErrorMessage();
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 格式化大小和偏移量
// 参数:
// [in] dwOffsetLow 低位偏移量
// 返回:
// RET_BADARG 参数非法
// RET_FILENOTOPENNED 文件未打开
// RET_FILEPROCESSING 文件正在操作
// RET_OK 操作成功
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 移动映射文件指针
// 参数:
// [in] dwOffsetLow 低位偏移量
// 返回:
// RET_BADARG 参数非法
// RET_FILENOTOPENNED 文件未打开
// RET_FILEPROCESSING 文件正在操作
// RET_OK 操作成功
//////////////////////////////////////////////////
};
#endif // !defined(AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_)
// filemapping.cpp: implementation of the UC_FILEMAPPING class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "filemapping.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
//#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//构造函数
FileMapping::FileMapping() //
{
m_hMutex = CreateMutex( NULL, FALSE, "map" );
//没有类似上面的指令创建互斥对象,下面指令怎么可以使用呢?
//推断在UC_FILEMAPPING的UC_LOG类中的构造函数中一定调用函数类似
//m_hMutex= CreateMutex( NULL, FALSE, szMutex );//szMutex为一互斥对象的名字
WaitForSingleObject( m_hMutex, INFINITE ); //应该是m_hFileOP吧 m_hMutex找不到定义
//初始化句柄
m_hPhysicsFile = NULL; //物理文件句柄
m_hMappingFile = NULL; //映射文件句柄
m_hFileOP = NULL; //文件操作互斥量
//初始化标志
m_isFileLoaded = FALSE; //工作状态标志
m_isMyHandle = FALSE; //是否是自己创建的文件映射
//初始化文件成员变量
m_pusMapInfo = NULL; //映射内存头信息
m_lpAddress = NULL; //映射文件地址指针
m_lpCursor = NULL; //映射游标地址指针
//得到系统的最小内存单位
SYSTEM_INFO SysInfo;
GetSystemInfo( &SysInfo );
m_dwSysAlloc = SysInfo.dwAllocationGranularity; //系统分配内存的最小单位
ReleaseMutex( m_hMutex );
}
//析构函数
FileMapping::~FileMapping()
{
m_hMutex = CreateMutex( NULL, FALSE, "map" );
WaitForSingleObject( m_hMutex, INFINITE );
//文件处理互斥操作
WaitForSingleObject( m_hFileOP, INFINITE );
//关闭映射内存头信息指针
if ( m_pusMapInfo )
delete m_pusMapInfo;
//关闭句柄
ReleaseMutex( m_hFileOP );
//只有创建者才有权关闭句柄
if ( m_isMyHandle ){
CloseHandle( m_hPhysicsFile );
CloseHandle( m_hMappingFile );
CloseHandle( m_hFileOP );
}
ReleaseMutex( m_hMutex );
}
//新建文件
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 打开映射文件
// 参数:
// [in] lpszFilePath 物理文件路径
// [in] lpszMappingName 映射内存命名
// [in] dwSizeLow 低位空间大小
// 返回:
// RET_BADARG 参数非法
// RET_FILEOPENNED 文件已经打开
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD FileMapping::Open(LPCTSTR lpszFilePath, LPCTSTR lpszMappingName, DWORD dwSizeLow)
{
//状态监测
if ( m_isFileLoaded )//初始值为FALSE
return RET_FILEOPENNED;
//参数监测
if ( lpszMappingName==NULL )
return RET_BADARG;
DWORD dwRet = RET_OK;
//创建文件操作互斥句柄
char szMutex[_MAX_PATH];
memset( szMutex, 0, _MAX_PATH );//字符数组中的元素全部置0
sprintf( szMutex, "%s_MUTEX", lpszMappingName );//以映射名称作为互斥对象名称,来确保在指定时刻只有
//一个线程在访问文件映射
m_hFileOP = CreateMutex( NULL, FALSE, szMutex );
WaitForSingleObject( m_hFileOP, INFINITE );
//创建对应的物理文件
if ( lpszFilePath!=NULL )
{
//新建文件
m_hPhysicsFile = CreateFile( lpszFilePath, GENERIC_READ|GENERIC_WRITE, 0, //generic
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
//如果文件存在, 打开现有文件,如果上面指令调用CreateFile函数的返回值为INVALID_HANDLE_VALUE说明指定的文件存在
if ( m_hPhysicsFile==INVALID_HANDLE_VALUE )
{
GetErrorMessage();
m_hPhysicsFile = CreateFile( lpszFilePath, GENERIC_READ|GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
}//参数中一个是CREATE_NEW表示新建,一个是OPEN_EXISTING表示打开一个已有的文件。
if(dwSizeLow==0 && m_hPhysicsFile!=INVALID_HANDLE_VALUE)
{
dwSizeLow=GetFileSize(m_hPhysicsFile,NULL );
}
}
if ( m_hPhysicsFile==INVALID_HANDLE_VALUE )
{
GetErrorMessage();
m_hPhysicsFile = NULL;
dwRet = RET_FILEERR;//line 271
}
else{
//创建映射文件(实际长度比申请长度多头信息的长度)
if ( dwRet==RET_OK ){
if ( m_hPhysicsFile==NULL ){
m_hMappingFile = CreateFileMapping( (HANDLE)NOPHYSICALFILE, NULL, PAGE_READWRITE,
0, dwSizeLow, lpszMappingName );
}
else{
m_hMappingFile = CreateFileMapping( m_hPhysicsFile, NULL, PAGE_READWRITE,
0, dwSizeLow + INFO_LEN, lpszMappingName );
}
if ( m_hMappingFile==NULL ){
GetErrorMessage();
CloseHandle( m_hPhysicsFile );
m_hPhysicsFile = NULL;
dwRet = RET_FILEERR;
}
else{
//获得对应的映射地址
m_lpAddress = MapViewOfFile( m_hMappingFile, FILE_MAP_ALL_ACCESS,
0, 0, 0 );
if ( m_lpAddress==NULL ){
dwRet = RET_FILEERR;
}
else{
//保存映射内存头信息
if ( m_pusMapInfo==NULL )
m_pusMapInfo =new US_MAPINFO; //US_MAPINFO
//PUS_MAPINFO m_pusMapInfo;
m_pusMapInfo->count=1;
m_pusMapInfo->dwSizeLow = dwSizeLow + INFO_LEN;//????头信息长度 info len
//上一句基本看懂了,dwSizeLow 是指映射文件的长度,INFO_LEN指映射文件对象自身信息的
//长度,加起来的长度是映射文件,在头部加了自身信息后的总长度,这些信息存放到文件映射头部
memset( m_pusMapInfo->szMappingName, 0, _MAX_PATH );
memcpy( m_pusMapInfo->szMappingName, lpszMappingName, strlen(lpszMappingName) );
memmove((LPBYTE) m_lpAddress+ INFO_LEN,(LPBYTE) m_lpAddress, dwSizeLow );
memcpy( m_lpAddress, m_pusMapInfo, INFO_LEN ); //映射文件地址指针m_lpAddress
//如果原来映射中有数据的话,是否会被覆盖。
//保存申请获得的开始地址和初始化游标信息
//这里其实真正的其实地址因为包含了头部信
//息, 为此需要移动到空白部分
m_lpAddress =m_lpCursor= (LPVOID)( (LPBYTE)m_lpAddress + INFO_LEN );
//设置打开标志信息
m_isFileLoaded = TRUE;
m_isMyHandle = TRUE;
}
}
}
}
ReleaseMutex( m_hFileOP );
if ( dwRet!=RET_OK )
CloseHandle( m_hFileOP );
return dwRet;
}
//打开一个已有命名内存映射文件
DWORD FileMapping::Open(LPCTSTR lpszMappingName)
{
//状态监测
if ( m_isFileLoaded || m_hFileOP )
return RET_FILEOPENNED;
//参数监测
if ( lpszMappingName==NULL )
return RET_BADARG;
DWORD dwRet = RET_OK;
//创建文件操作互斥句柄
char szMutex[_MAX_PATH];
memset( szMutex, 0, _MAX_PATH );
sprintf( szMutex, "%s_MUTEX", lpszMappingName );
m_hFileOP = OpenMutex( MUTEX_ALL_ACCESS, FALSE, szMutex );
if ( m_hFileOP==NULL ){
return RET_FILENOTOPENNED;
}
WaitForSingleObject( m_hFileOP, INFINITE );
//打开映射文件
m_hMappingFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpszMappingName );
if ( m_hMappingFile==NULL ){
dwRet = RET_FILEERR;
}
else{
//获得对应的映射地址
m_lpAddress = MapViewOfFile( m_hMappingFile, FILE_MAP_ALL_ACCESS,
0, 0, 0 );
if ( m_lpAddress==NULL ){
dwRet = RET_FILEERR;
}
else{
//获得映射内存头信息
if ( m_pusMapInfo==NULL )
m_pusMapInfo = new US_MAPINFO;
memcpy( m_pusMapInfo, m_lpAddress, INFO_LEN );
m_pusMapInfo->count++; //表示打开的文件映射数增加了一。
memcpy( m_lpAddress, m_pusMapInfo, INFO_LEN ); //把增加后的信息写回到文件映射的头部
//保存地址和游标
//同创建时候的原理
m_lpAddress = m_lpCursor = (LPVOID)( (LPBYTE)m_lpAddress + INFO_LEN );
//设置打开标志信息
m_isFileLoaded = TRUE;
m_isMyHandle = TRUE;
}
}
ReleaseMutex( m_hFileOP );
return dwRet;
}
//关闭文件
DWORD FileMapping::Close(BOOL wantDump)
{
//状态监测
if ( m_isFileLoaded==FALSE ) //工作状态标志
return RET_FILENOTOPENNED;
DWORD dwRet = RET_OK;
WaitForSingleObject( m_hFileOP, INFINITE );
m_pusMapInfo->count--;
if( m_pusMapInfo->count==0 )
{
memmove((LPBYTE) m_lpAddress- INFO_LEN,(LPBYTE) m_lpAddress, m_pusMapInfo->dwSizeLow-INFO_LEN );
}
if ( wantDump )
FlushView();
delete m_pusMapInfo;
m_pusMapInfo = NULL; //映射内存头信息
m_isFileLoaded = FALSE; //工作状态标志
ReleaseMutex( m_hFileOP );
//只有创建者才有权利关闭句柄
if ( m_isMyHandle==FALSE ){ //是否是自己创建的文件映射
CloseHandle( m_hPhysicsFile );
CloseHandle( m_hMappingFile );
CloseHandle( m_hFileOP );
}
return dwRet;
}
//读取映射文件
//////////////////////////////////////////////////
// 作者: 张旻
// 创建: 2002.01.16
// 功能: 读取映射文件
// 参数:
// [in] lpBuf 缓冲区
// [in] nSize 缓冲区大小
// [in] dwOffsetLow 偏移地址地位
// 返回:
// RET_BADARG 参数非法
// RET_BUFFERTOBIG 缓存区过大
// RET_BUFFEROVERFLOW 缓冲区溢出
// RET_FILENOTOPENNED 文件未打开
// RET_FILEPROCESSING 文件正在操作
// RET_FILEERR 文件操作失败
// RET_OK 操作成功
//////////////////////////////////////////////////
DWORD FileMapping::Read(LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow )
{
//状态监测
if ( m_isFileLoaded==FALSE ) //工作状态标志
return RET_FILENOTOPENNED;
//参数监测
if ( lpBuf==NULL || nSize==0 )
return RET_BADARG;
DWORD dwRet = RET_OK;
WaitForSingleObject( m_hFileOP, INFINITE );
//计算内容是否溢出
UINT nSizeUsed = (UINT)( LPBYTE(m_lpCursor) - LPBYTE(m_lpAddress) );
if ( nSize<nSizeUsed ){
dwRet = RET_BUFFEROVERFLOW;
}
else{
//读出信息
//nSize = nSizeUsed;
memcpy( lpBuf, (LPVOID)( (LPBYTE)m_lpAddress + dwOffsetLow ), nSize );
}
ReleaseMutex( m_hFileOP );
return dwRet;
}
//写入映射文件
DWORD FileMapping::Write(LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow, BOOL isAppend )
{
//状态监测
if ( m_isFileLoaded==FALSE ) //工作状态标志
return RET_FILENOTOPENNED;
//参数监测
if ( lpBuf==NULL || nSize==0 )
return RET_BADARG;
DWORD dwRet = RET_OK;
WaitForSingleObject( m_hFileOP, INFINITE );
//计算内容是否溢出
UINT nLeftSize = (UINT)m_pusMapInfo->dwSizeLow - (UINT)( LPBYTE(m_lpCursor) - LPBYTE(m_lpAddress) )
- INFO_LEN;
if ( nLeftSize<nSize ){
dwRet = RET_BUFFEROVERFLOW;
}
else{
//根据模式移动游标
if ( isAppend==FALSE ){
m_lpCursor = (LPVOID)( (LPBYTE)m_lpAddress + dwOffsetLow );
}
//写入信息
memcpy( m_lpCursor, lpBuf, nSize );
//移动游标
if ( isAppend )
m_lpCursor = (LPVOID)( (LPBYTE)m_lpCursor + nSize );
}
ReleaseMutex( m_hFileOP );
return dwRet;
}
//获得错误信息
DWORD FileMapping::GetErrorMessage()
{
DWORD dwRet = GetLastError();
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwRet,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
//MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
//TRACE( "0x%08X: %s\n", dwRet, lpMsgBuf );
// Free the buffer.
LocalFree( lpMsgBuf );
return dwRet;
}
//得到映射文件大小
DWORD FileMapping::GetSize()
{
if ( m_isFileLoaded==FALSE )
return RET_FILENOTOPENNED;
if ( m_pusMapInfo )
return m_pusMapInfo->dwSizeLow - INFO_LEN;
else
return -1;
}
//输出内容
DWORD FileMapping::FlushView()
{
//状态监测
if ( m_isFileLoaded )
{
if ( m_lpCursor > m_lpAddress && m_hPhysicsFile )
{
SIZE_T nSize = (SIZE_T)( (LPBYTE)m_lpCursor - (LPBYTE)m_lpAddress );
if ( FlushViewOfFile( m_lpAddress, nSize ) )
return RET_OK;
else
return RET_FILEERR;
}
return RET_OK;
}
else{
return RET_FILENOTOPENNED;
}
}