关于共享内存例子,强烈推荐《Windows高级编程指南》(第三版),清华大学出版社。

解决方案 »

  1.   

    请问大侠Sniper,《Windows高级编程指南》(第三版)有电子文档吗? 可否发给小弟一份? mail: [email protected]
      

  2.   

    这是一个封装之后的文件,耐心读读,相信对你会有帮助的://$//////////////////////////////////////////////////////////////
    //$ RDMapFile.h
    //$
    //$ Author      : Flying YE
    //$ Version     : 1.00.000
    //$ Create Time : 1999年7月13日17:39
    //$ LastModified: 1999年7月29日12:26
    //$ Descriptions: 内存映射文件
    //$
    //$//////////////////////////////////////////////////////////////
    #if !defined(AFX_MAPFILE_H__7A967555_2844_11D3_A339_000021EB448D__INCLUDED_)
    #define AFX_MAPFILE_H__7A967555_2844_11D3_A339_000021EB448D__INCLUDED_#if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000#pragma pack(push)
    #pragma pack(8)//简记符号
    #define TMFHdr template<class T>
    #define TMFClass CMapFile<T>
    ////////////////////////////////////////////////////////////
    // 内存表的映射对象信息包
    // SeeAlso: ::GetRDTableMemoInfo(...);
    //
    typedef struct __tag_TableMemoInfo {
    TCHAR m_szName[80]; //映射对象唯一名称 DWORD* m_lpObjs; //指向T对象数组的指针
    //DWORD m_dwCount; //T对象元素在内存中的个数(包含了预保留的供添加的入口数目)
    //DWORD m_dwMaxCount; //T对象元素总的个数(也是实际的元素总数) DWORD m_dwBaseAddr; //内存映射基地址
    DWORD m_dwMapSize; //内存映射区域尺寸 DWORD m_dwMaxSizeLow; //对象实际的全尺寸(Low, in bytes)
    DWORD m_dwMaxSizeHigh; //对象实际的全尺寸(High,in bytes)
    //BOOL m_bIsReady; //内存映射对象准备就绪?(reserved)
    //CRITICAL_SECTION m_csWriting; //当拥有者写入时,锁定整个表以禁止其他一切读写
    HANDLE m_hMutexModifying; //当修改表时,锁定整个表以禁止其他一切修改操作
    UINT m_nTimeOut; //当锁定表时,要等待的超时值 //#if defined(RD_ONLY)
    //RD内部保留的标识域。如果使用,可能导致未知后果。
    HFILE m_hFileMap; //物理的映射文件的句柄
    HANDLE m_hFileMapView; //内存映射区域的句柄
    DWORD m_dwMapPosInFileLow; //文件中的映射基址(Low)
    DWORD m_dwMapPosInFileHigh; //文件中的映射基址(High)
    BOOL m_bIsSorted; //排序吗? 备用
    //#else
    // DWORD reserved[5];
    //#endif
    } TABLEMEMOINFO, FAR* LPTABLEMEMOINFO;
    /////////////////////////////////////////////////////////////
    // 映射文件对象管理器类(CMapFile)模板定义
    //目标:
    // 1 完成对象数组的表化,即处理为一张数据库表,并提供表式的访问接口
    // 2 提供表的内存管理功能,使表被完全缓冲于一个内存区域。其他进程通
    // 过映射能够直接读取表记录。
    // 但,不允许其他进程直接写入,增删或修改表记录。
    /////////////////////////////////////////////////////////////
    TMFHdr
    class CMapFile : public CObject {
    BOOL m_bIsOwner; //内存映射对象仅仅由拥有者创建,而其
    //他进程只能进行关联。本成员确定本实
    //例是否是创建者(当前版本:RD_ONLY)
    public:
    CMapFile();
    virtual ~CMapFile(); //映射对象(标准表,实时表)的内存信息包
    protected:
    //WS, CS必须在完成映射之后,传送指针到m_objs中(参考Attach(), Detach())
    //RD负责m_objs的创建,空间分配,撤消等等工作。(参考Create(), Destroy()) //管理信息包
    TABLEMEMOINFO m_tmi; //映射区域管理用的信息包
    //实际存储记录数组之处
    T* m_objs(){
    LPBYTE p = (LPBYTE)m_tmi.m_lpObjs;
    p += 2*sizeof(DWORD)+sizeof(BOOL); //越过保留区域
    return (T*)p; }
    T* m_objs2()const{
    LPBYTE p = (LPBYTE)m_tmi.m_lpObjs;
    p += 2*sizeof(DWORD)+sizeof(BOOL); //越过保留区域
    return (T*)p; }
    //返回实际分配的元素个数
    DWORD m_dwCount()const{ return ((DWORD*)m_tmi.m_lpObjs)[0]; }
    void SetCount(DWORD cnt){ ((DWORD*)m_tmi.m_lpObjs)[0]=cnt; }
    //返回请求初始化的元素个数
    DWORD m_dwMaxCount()const{ return ((DWORD*)m_tmi.m_lpObjs)[1]; }
    void SetMaxCount(DWORD cnt){ ((DWORD*)m_tmi.m_lpObjs)[1]=cnt; }
    public:
    //本表 是否已经初始化完成,并处于就绪态
    BOOL m_bIsReady()const{ return *(BOOL*) (((DWORD*)m_tmi.m_lpObjs)+2); }
    //设置本表进入就绪状态? (set val=1:ready, val=0:not ready)
    void SetReady(DWORD val){ *(BOOL*) (((DWORD*)m_tmi.m_lpObjs)+2)=val; }
    protected:
    //SetObjectPtr提供修改内存映射区域指针的能力 (备用)
    void SetObjectPtr(T* lpT){ m_tmi.m_lpObjs=(DWORD*)lpT; }
    void SetObjectPtr(LPVOID lpT){ m_tmi.m_lpObjs=(DWORD*)lpT; }public:
    //是处于调试模式吗?
    BOOL IsInDebugMode();
    //使用了物理交换文件吗? (目前总是不使用)
    BOOL IsPhysicalFileUsed(){ return hFile==(HFILE)-1; } //设置写锁定操作的超时等待时间(ms)
    void SetTimeOut(UINT nTimeOut = 10){ m_tmi.m_nTimeOut = nTimeOut; } //返回可供访问的相应区域的指针和已有数据数量(in dwCount)。
    // 这是超时式调用(直到获得访问权、或者超时时为止)
    //如果超时失败返回,则返回值dwCount为-1, vg中值无效(不可用)
    DWORD BeginAccessSession(T*& pObject){
    DWORD dwRet = WaitForSingleObject(m_tmi.m_hMutexModifying, m_tmi.m_nTimeOut);
    if(dwRet == WAIT_OBJECT_0){
    pObject = m_objs();
    return GetUpperBound();
    }
    return (DWORD)-1; //WAIT_TIMEOUT, WAIT_ABANDONED
    }
    //结束访问工作
    BOOL EndAccessSession(BOOL bNeedClearAll = FALSE){
    if(bNeedClearAll)
    SetUpperBound(0);
    return ReleaseMutex(m_tmi.m_hMutexModifying);
    }private:
    //内部使用//
    BOOL IsNeedPhysicalFile(){ return !(m_tmi.m_dwMapSize==m_tmi.m_dwMaxSizeLow && m_tmi.m_dwMaxSizeHigh==0); }public:
    //返回映射区域管理信息包
    const LPTABLEMEMOINFO GetTableMemoInfoPtr()const{
    //dup m_csWriting
    return (const LPTABLEMEMOINFO)&m_tmi;
    }
    //返回内存映射对象的标识符名称
    LPCTSTR GetObjectName(){ return m_tmi.m_szName; }protected:
    //返回物理文件名称
    CString GetPhyFilename();public:
    //从给出的内存映射信息完成内存的映射关联,并构造出CMapFile对象实例。
    //当内存映射对象构造失败时,返回FALSE。
    //Only For CS, WS, ...
    BOOL Attach(LPCTSTR szTableName);
    //从给出的内存映射信息完成内存的映射关联,并构造出CMapFile对象实例。
    //当内存映射对象构造失败时,返回FALSE。
    //Only For CS, WS, ...
    BOOL Attach(LPTABLEMEMOINFO lpTableMemoInfo);
    //清除通过Attach()关联的内存映射对象
    //Only For CS, WS, ...
    BOOL Detach();public:
    //创建内存映射对象(RD_ONLY),不能由CS,WS调用
    //说明:
    //  整个被映射的对象数组所需要的空间由对象的尺寸和对象的元素个数决定,该对
    //象会使用一个物理文件进行缓冲。
    //  然而,如果指定‘内存中的映射空间尺寸’等于最大空间,CMapFile管理器自动
    //地使用完整内存映射方案,而忽略物理缓冲文件的使用。
    //  整个数组为预分配固定尺寸的模式。所有表记录均被加载到内存中,当使用
    //AddNew()添加元素时,管理器从预先保留的元素空槽中取出空间分配个新元素,直
    //到保留空间用尽时为止。
    //  缺省方式下,依据内存粒度的大小和元素的尺寸,我们仍然能够获得一定的保留
    //空间。为了明确数组中剩余的保留空槽个数,可以使用GetFreeSlotCount()。
    BOOL Create(DWORD dwMaxCount, //数组的元素个数 
    LPCTSTR szName, //映射文件对象的标识名称
    DWORD dwBaseAddr=0, //内存中的映射基地址
    DWORD dwMapCount=0, //内存中的映射空间尺寸
    DWORD dwReservedCount=0 //数组应该预先保留以供增加的数目
    );
    //清除使用Create()创建的内存映射对象(RD_ONLY)
    BOOL Destroy(); //获取数组中剩余的保留空槽个数。
    DWORD GetFreeSlotCount(){ return m_dwCount() - m_dwMaxCount(); }public:
    //表操作 // --------- 动态数组支持 ----------- //增添一条新记录。必要时需要扩充数组的内存区域。
    //  但目前我们只提供简易办法:预先在分配空间时保留出数个元素的存储空间,而在
    //  新增时仅仅简单地取用这些空间。如果超出,则抛出内存异常。
    //
    //   -- 当锁定表时超时,或者其他异常时,返回FALSE
    BOOL AddNew(const T& obj);
    //在指定位置插入一条新记录。必要时需要扩充数组的内存区域。
    //  但目前我们只提供简易办法:预先在分配空间时保留出数个元素的存储空间,而在
    //  新增时仅仅简单地取用这些空间。如果超出,则抛出内存异常。
    //
    //   -- 当锁定表时超时,或者其他异常时,返回FALSE
    BOOL InsertAt(DWORD index, const T& obj);
    //删除指定下标处的表记录,并缩减数组尺寸。
    //  但目前我们只提供简易办法:预先在分配空间时保留出数个元素的存储空间,而在
    //  新增时仅仅简单地取用这些空间。如果超出,则抛出内存异常。
    //
    //   -- 当锁定表时超时,或者其他异常时,返回FALSE
    BOOL DeleteAt(DWORD index);
    //数组操作 //返回数组的请求个数(不是实际分配了内存空间的个数)
    DWORD GetUpperBound() const { return m_dwMaxCount(); }
    //返回数组的实际分配的元素个数(不是原始请求的个数)
    //  目前我们提供简易办法:预先在分配空间时保留出数个元素的存储空间,而在
    //  新增时仅仅简单地取用这些空间。如果超出,则抛出内存异常。
    //
    DWORD GetUpperBoundInMemo() const { return m_dwCount(); } //访问指定下标处的元素。如果给出的下标非法,将可能导致运行时错误。
    //   不能使用非法下标,因为返回的T&参考完全没有意义。
    T& ElementAt(DWORD index) const;
    //访问指定下标处的元素。如果给出的下标非法,将可能导致运行时错误。
    //   不能使用非法下标,因为返回的T&参考完全没有意义。
    T& operator [] (DWORD index) const { return ElementAt(index); } // --------- 静态,数组元素设置 ----------- //设定指定下标处的元素的值。如果给出的下标非法,将可能导致运行时错误。
    //   -- 当锁定表时超时,或者其他异常时,返回FALSE
    BOOL SetAt(DWORD index, const T&);
    BOOL SetAt(DWORD index, const T* pObjs, DWORD dwCount = 1);
    // --------- 动态数组支持 -----------
    public:
    //调整数组的尺寸。新尺寸不能超过空间的预保留上限。
    BOOL  SetUpperBound(DWORD dwNewSize){
    if(dwNewSize <= m_dwCount()){
    SetMaxCount(dwNewSize);
    return TRUE;
    }
    return FALSE;
    } //用给出的元素数组(pObjs, 个数 dwCount)来重新格式化共享内存。
    //   -- 当锁定表时超时,或者其他异常时,返回FALSE
    //!!注意:数组中原有的元素将被抛弃。
    BOOL CopyArrayFrom(const T* pObjs, DWORD dwCount = 1){
    if(SetUpperBound(dwCount))
    return SetAt(0, pObjs, dwCount);
    return FALSE;
    }
    };
    TMFHdr
    inline TMFClass::CMapFile(){
    m_bIsOwner = FALSE;
    ::memset((LPVOID)&m_tmi, 0, sizeof(m_tmi));
    SetTimeOut();
    }TMFHdr
    inline TMFClass::~CMapFile(){
    }
    TMFHdr
    inline BOOL TMFClass::AddNew(const T& obj){
    if(GetFreeSlotCount()<1) return FALSE; DWORD idx; T* p;
    idx = BeginAccessSession(p);
    if(idx == (DWORD)-1) //WAIT_TIMEOUT, WAIT_ABANDONED
    return FALSE; if(m_bIsReady()){
    SetUpperBound(idx+1);
    SetAt(idx, obj);
    }
    return EndAccessSession();
    }TMFHdr
    inline BOOL TMFClass::InsertAt(DWORD index, const T& obj){
    if(GetFreeSlotCount()<1) return FALSE; DWORD idx; T* p;
    idx = BeginAccessSession(p);
    if(idx == (DWORD)-1) //WAIT_TIMEOUT, WAIT_ABANDONED
    return FALSE; if(m_bIsReady()){
    memmove( p + index, p + index + 1,
    (m_dwMaxCount() - index) * sizeof(T) );
    SetUpperBound(GetUpperBound()+1);
    SetAt(index, obj);
    }
    return EndAccessSession();
    }TMFHdr
    inline BOOL TMFClass::DeleteAt(DWORD index){
    DWORD idx; T* p;
    idx = BeginAccessSession(p);
    if(idx == (DWORD)-1) //WAIT_TIMEOUT, WAIT_ABANDONED
    return FALSE; if(m_bIsReady()){
    memmove( p + index, m_objs() + index - 1,
    (GetUpperBound() - index) * sizeof(T) );
    SetUpperBound(GetUpperBound()-1);
    }
    return EndAccessSession();
    }
    TMFHdr
    inline BOOL TMFClass::SetAt(DWORD index, const T& obj){
    ASSERT(index<GetUpperBound() && index>=0);
    //ASSERT(m_bIsOwner); DWORD idx; T* p;
    idx = BeginAccessSession(p);
    if(index == (DWORD)-1) //WAIT_TIMEOUT, WAIT_ABANDONED
    return FALSE; if(m_bIsReady()){
    p[index] = obj;
    }
    return EndAccessSession();
    }
    TMFHdr
    inline BOOL TMFClass::SetAt(DWORD index, const T* pObjs, DWORD dwCount){
    ASSERT(index+dwCount<=GetUpperBound() && index>=0);
    //ASSERT(m_bIsOwner); DWORD idx, n; T* p;
    idx = BeginAccessSession(p);
    if(idx == (DWORD)-1) //WAIT_TIMEOUT, WAIT_ABANDONED
    return FALSE; if(m_bIsReady()){
    n = 0;
    while(n<dwCount){
    m_objs()[index++] = pObjs[n++];
    }
    }
    return EndAccessSession();
    }
    TMFHdr
    inline T& TMFClass::ElementAt(DWORD index)const{
    //if(!m_bIsReady())
    // return T(); ASSERT(index<GetUpperBound() && index>=0);
    return m_objs2()[index];
    }
    /////////////////////////////////////////////////////////////////
    //Attach版本 1:通过 预定义表名字 来共享
    /////////////////////////////////////////////////////////////////
    TMFHdr 
    inline BOOL TMFClass::Attach(LPCTSTR szTableName){
    //#ifdef RD_ONLY
    // AfxMessageBox("存在RD_ONLY标志,不允许调用Attach(), Detach()。");
    // ASSERT(0);
    // return FALSE;
    //#endif

    m_bIsOwner = FALSE;
    _tcscpy(m_tmi.m_szName, szTableName);
    m_tmi.m_hFileMap = (HFILE)INVALID_HANDLE_VALUE;
    m_tmi.m_dwMapPosInFileLow  = 0;
    m_tmi.m_dwMapPosInFileHigh = 0;
    {
    CString str = _T("Mutex-");
    str += GetObjectName();
    m_tmi.m_hMutexModifying = OpenMutex(MUTEX_ALL_ACCESS, FALSE, str);
    }
    if(!m_tmi.m_hMutexModifying){
    CString msg; msg.Format(IDS_RD_MODULE_ABSENT, AfxGetAppName());
    AfxMessageBox(msg);
    //为了加强CS,WS对实时数据库模块的运行依赖性,考虑在此返回
    //return FALSE;
    } m_tmi.m_hFileMapView = ::OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE,
    FALSE, GetObjectName());
    if(!m_tmi.m_hFileMapView)
    return FALSE;

    LPVOID lpView = ::MapViewOfFile(m_tmi.m_hFileMapView,
    FILE_MAP_READ | FILE_MAP_WRITE, //NOTICE, Attacher can modify!
    0,0,0);
    if(!lpView){
    ::CloseHandle(m_tmi.m_hFileMapView);
    return FALSE;
    } m_tmi.m_lpObjs = (DWORD*)lpView;

    TRACE("映射<MapView>表 (%s) ATTACH OK. 数组上界:%d, 数组实际上界:%d, 保留槽数: %d。\n",
    GetObjectName(),
    GetUpperBound(), GetUpperBoundInMemo(), GetFreeSlotCount());
    return TRUE;
    }/////////////////////////////////////////////////////////////////
    //Attach版本 2:通过传递TableMemoInfo管理信息包来共享
    //兴义不使用
    /////////////////////////////////////////////////////////////////
    TMFHdr 
    inline BOOL TMFClass::Attach(LPTABLEMEMOINFO lpTableMemoInfo){
    //#ifdef RD_ONLY
    // AfxMessageBox("存在RD_ONLY标志,不允许调用Attach(), Detach()。");
    // ASSERT(0);
    // return FALSE;
    //#endif

    m_bIsOwner = FALSE; //duplicate and re-generate tmi structure
    memcpy((LPVOID)&m_tmi, lpTableMemoInfo, sizeof(m_tmi));
    m_tmi.m_hFileMap = (HFILE)INVALID_HANDLE_VALUE;
    m_tmi.m_dwMapPosInFileLow  = 0;
    m_tmi.m_dwMapPosInFileHigh = 0;
    {
    CString str = _T("Mutex-");
    str += GetObjectName();
    m_tmi.m_hMutexModifying = OpenMutex(MUTEX_ALL_ACCESS, FALSE, str);
    }
    if(!m_tmi.m_hMutexModifying){
    CString msg; msg.Format(IDS_RD_MODULE_ABSENT, AfxGetAppName());
    AfxMessageBox(msg);
    //return FALSE;
    } //and, attach map-view
    m_tmi.m_hFileMapView = ::OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE,
    FALSE, GetObjectName());
    if(!m_tmi.m_hFileMapView)
    return FALSE;

    LPVOID lpView = ::MapViewOfFile(m_tmi.m_hFileMapView,
    FILE_MAP_READ, //|FILE_MAP_WRITE,
    0,0,0);
    if(!lpView){
    ::CloseHandle(m_tmi.m_hFileMapView);
    return FALSE;
    } m_tmi.m_lpObjs = (LPBYTE)lpView;
    TRACE("映射<MapView>表 (%s) ATTACH OK. Preserved Slot count is: %d.\n",
    GetObjectName(),
    GetFreeSlotCount());
    return TRUE;
    }TMFHdr
    inline BOOL TMFClass::Detach(){
    if(m_bIsOwner){
    //通知其他进程撤除映射...
    SetReady(FALSE);
    //... //撤消内存映射
    //DeleteCriticalSection(&m_tmi.m_csWriting);
    if(m_tmi.m_lpObjs){
    ::UnmapViewOfFile(m_tmi.m_lpObjs);
    m_tmi.m_lpObjs = NULL;
    }
    if(m_tmi.m_hFileMapView){
    ::CloseHandle(m_tmi.m_hFileMapView);
    m_tmi.m_hFileMapView = INVALID_HANDLE_VALUE;
    }
    if(m_tmi.m_hFileMap!=(HFILE)INVALID_HANDLE_VALUE){
    ::CloseHandle((HANDLE)m_tmi.m_hFileMap);
    m_tmi.m_hFileMap = (HFILE)INVALID_HANDLE_VALUE;
    }
    }
    else{
    ::UnmapViewOfFile(m_tmi.m_lpObjs);
    m_tmi.m_lpObjs = NULL;
    ::CloseHandle(m_tmi.m_hFileMapView);
    m_tmi.m_hFileMapView = INVALID_HANDLE_VALUE;
    } CloseHandle(m_tmi.m_hMutexModifying); TRACE("映射<MapView>表 (%s) DESTROY OK.\n", GetObjectName());
    return TRUE;
    }TMFHdr
    inline CString TMFClass::GetPhyFilename(){
    CString strFile;
    strFile = GetObjectName(); strFile+=".rd";
    //temppath
    return strFile;
    }TMFHdr
    inline BOOL TMFClass::IsInDebugMode(){
    //稍后,应该使用工程信息定义表中的信息来决定是否处于调试模式。
    return TRUE;
    }/////////////////////////////////////////////////////////////////
    TMFHdr
    inline BOOL TMFClass::Create(DWORD dwMaxCount, LPCTSTR szName,
     DWORD dwBaseAddr, DWORD dwMapCount, DWORD dwPreservedCount){
    #ifndef RD_ONLY
    AfxMessageBox("不存在RD_ONLY标志,不允许调用Create(), Destroy()。");
    ASSERT(0);
    return FALSE;
    #endif
    ASSERT(m_tmi.m_hFileMapView==NULL || m_tmi.m_hFileMapView!=INVALID_HANDLE_VALUE); m_bIsOwner = TRUE;
    //InitializeCriticalSection(&m_tmi.m_csWriting);
    {
    CString str = _T("Mutex-");
    str += szName;
    m_tmi.m_hMutexModifying = CreateMutex(NULL, FALSE, str);
    }
    ASSERT(m_tmi.m_hMutexModifying);
    BOOL isNeedPhyFile = IsNeedPhysicalFile(); DWORD mapcnt = dwMapCount==0? dwMaxCount: dwMapCount;
    mapcnt += dwPreservedCount; //注意:尺寸的计算算法只适应小于2**32-1的对象
    m_tmi.m_dwMaxSizeLow = sizeof(T) * dwMaxCount; //对象的完整尺寸
    m_tmi.m_dwMaxSizeHigh = 0; _tcsncpy(m_tmi.m_szName, szName, 80); //标识符 m_tmi.m_dwBaseAddr = dwBaseAddr; //映射位置
    m_tmi.m_dwMapSize = mapcnt * sizeof(T);
    //圆整映射尺寸到内存粒度边界上:
    SYSTEM_INFO si;
    ::GetSystemInfo(&si); DWORD g = si.dwAllocationGranularity;
    m_tmi.m_dwMapSize /= g; m_tmi.m_dwMapSize++;
    m_tmi.m_dwMapSize *= g;
    mapcnt = m_tmi.m_dwMapSize / sizeof(T); //圆整后实际能容纳的元素个数

    HFILE hFile;
    if(isNeedPhyFile){
    hFile = (HFILE)::CreateFile( GetPhyFilename(), GENERIC_READ|GENERIC_WRITE,
    IsInDebugMode()? FILE_SHARE_READ: 0,
    NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
    if(hFile == (HFILE)INVALID_HANDLE_VALUE)
    return FALSE; //创建失败
    }
    else
    hFile = (HFILE)-1; HANDLE hMap;
    if( NULL == (hMap = ::CreateFileMapping((HANDLE)hFile, NULL, PAGE_READWRITE, 
    0, m_tmi.m_dwMapSize, GetObjectName() )) ){
    if(hFile!=(HFILE)-1) ::CloseHandle((HANDLE)hFile);
    return FALSE;
    } if(::GetLastError()==ERROR_ALREADY_EXISTS){
    HWND hwnd = NULL;
    ::MessageBox(hwnd, "Mapping has already exists. ", 
    "CANNOT CREATE MAP…", MB_OK);
    ::CloseHandle(hMap);
    if(hFile!=(HFILE)-1) ::CloseHandle((HANDLE)hFile);
    return FALSE;
    } LPVOID lpView;
    lpView = ::MapViewOfFileEx(hMap, FILE_MAP_READ|FILE_MAP_WRITE, 0,0, 
    m_tmi.m_dwMapSize, (LPVOID)m_tmi.m_dwBaseAddr);
    if((BYTE*)lpView==NULL){
    ::CloseHandle(hMap);
    if(hFile!=(HFILE)-1) ::CloseHandle((HANDLE)hFile);
    return FALSE;
    } //DWORD dwOldProtect; //拒绝共享者直接写数据
    //::VirtualProtect( (LPVOID)m_tmi.m_dwBaseAddr, m_tmi.m_dwMapSize, 
    // PAGE_READONLY, &dwOldProtect ); m_tmi.m_lpObjs = (DWORD*)lpView;
    memset( m_tmi.m_lpObjs, 0, m_tmi.m_dwMapSize);
    m_tmi.m_hFileMap = hFile;
    m_tmi.m_hFileMapView = hMap;
    m_tmi.m_dwMapPosInFileLow  = 0;
    m_tmi.m_dwMapPosInFileHigh = 0;
    SetCount(mapcnt);
    SetMaxCount(dwMaxCount);
    TRACE("映射<MapView>表 (%s) CREATE OK. 数组上界:%d, 数组实际上界:%d, 保留槽数: %d。\n",
    GetObjectName(),
    GetUpperBound(), GetUpperBoundInMemo(), (int)GetFreeSlotCount());
    return TRUE;
    }TMFHdr
    inline BOOL TMFClass::Destroy(){ return Detach(); }////////////////////////////////////////////////////////////////////////////////
    #define CMemoryTable CMapFile
    //Example:
    //CMapFile<int> CMFIntArray();
    //CMFIntArray one;
    //one.Attach();
    //...
    //one.Detach();
    //return;#pragma pack(push)#endif // !defined(AFX_MAPFILE_H__7A967555_2844_11D3_A339_000021EB448D__INCLUDED_)