朝花夕拾(2)——内存文件映射用户类的修改

 

作者:青青子衿

email:anzijin@sina.com

 内存文件映射用户类的修改    
// 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;
    }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值