谁能给我一段实现共享内存的例子做参考?

puppy_he007 2000-06-12 05:38:00
加精
小弟遇到一个棘手的题目,老板要求做一个程序,能够从另一个应用程序中读取实时变化的数据, 这该怎么做呢? 哪位大侠来帮帮我吧.
...全文
342 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
jy 2000-06-15
  • 打赏
  • 举报
回复
这是一个封装之后的文件,耐心读读,相信对你会有帮助的:

//$//////////////////////////////////////////////////////////////
//$ 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_)
solar 2000-06-13
  • 打赏
  • 举报
回复
用动态连接库应该能做到
Sniper 2000-06-13
  • 打赏
  • 举报
回复
关于共享内存例子,强烈推荐《Windows高级编程指南》(第三版),清华大学出版社。
puppy_he007 2000-06-13
  • 打赏
  • 举报
回复
请问大侠Sniper,《Windows高级编程指南》(第三版)有电子文档吗? 可否发给小弟一份? mail: puppy_he007@21cn.com.
 OpenGL-自主高性能三维GIS平台架构与实现/第二季:实现三维GIS球体+ 高程数据章节名称DEM基础1DEM基础知识1.介绍基本的DEM知识2.什么是DEM,作用是什么2DEM数据1.如何获取/ 传统测量/激光扫描/无人机测量/ 点云数据/ 倾斜摄影2.如何使用/局部小规模(栅格数据,图片/tif),3. 组织方式4. 根据使用目的不同,介绍多种优化方法3DEM图层的实现原理14DEM数据结构定义struct  V3U3N4顶点数据的生成和计算WGS84投影计算5wgs84 投影球体被切成一个个小圆弧,一共60个投影带,分别为01,02.........60WGS的最新版本为WGS 84(也称作WGS 1984、EPSG:4326),1984年定义、最后修订于2004年。接口定义坐标转换Wgs84 数据加载6瓦片编号计算生成算法1. 经纬度到大地坐标的转换2.大地坐标到经纬度坐标转换3. 根据经纬度获取瓦片编号框架重构7智能指针重构框架1. 基类定义(所有的类继承自基类),基类派生自 std::enbale_shared_from_this2. 实现智能指针的动态转换接口3. 实现向下转换4. 已有的类实现全部使用智能指针重构5. 任务系统(多线程加载任务)8引入图层(Layer)1. 介绍图层的概念以及重要性2. 图层类实现3. 修改框架(使用图层的方式重构框架)9Layer-bug排查(绘制过程中出现错位,偶发)1. 框架重构后遇到问题(绘制结果错误)2. 瓦片索引方式发生变化,多线程中引起内存问题3. 修改索引方式,解决绘制偶发错误问题10引入数据源(TileSource)1. 数据源的作用与设计目的2. 当前存在的问题,数据调度中存在问题3. 数据源(TileSource)类实现11数据格式管理(FormatMgr)1. 数据格式管理(FormatMgr) 提出的目的,需要解决的问题2. CELLFormat基类接口抽象3. 实现几个标准格式类4. 修改框架流程,使用FormatMgr重构流程5. 扩展支持,后续支持任务格式数据加入系统12Task(任务)优化1. 任务中低耦合数据结构,目的是让Task更加的通用2. 修改任务读取代码与任务处理代码,完善处理流程DEM高程13DEM-数字高程定义1. 什么是数字化高程数据2. 当下GIS系统中有哪些常见的高程格式3. 课程体体系中使用的哪种格式4. 高程类定义以及实现,并加入到FormatMgr 管理系统中14高程瓦片数据读取1. 介绍GIS系统相关的工具(在数据转换)数据生成方面可以解决大量时间2. 自定义高程瓦片格式说明3. 自定义高程格式文件解析,并以智能对象的方式引入到系统中4. 完善框架代码,适配高程数据15高程瓦片文件的读取1. 实现基本的读取算法2. 增加格式化组件,并加入到系统中3. 配置高程图层以及高程数据源,并加载数据,验证数据正确性16瓦片数据结构重构1.顶点生成2.UV坐标计算3.面数据生成17DEM重构绘制流程1. 修改绘制数据结构,去除无用字段2. 增加Mesh类,实现光栅数据转换成三角面数据,计算UV数据,提炼接口3. 修改系统调度,实现顶点数据,UV数据,以及面数据的生成与更新4. 按需更新数据,而不是每一帧更新18DEM-数据精度问题(CPU)1. 因为瓦片数据使用大地坐标作为系统输入,造成瓦片坐标很大,单浮点数据精度不够2. 使用局部坐标的方式解决单浮点精度问题3. 调整相机参数,解决投影矩阵数据计算深度精度问题4. 修改绘制shader 实现对瓦片数据的绘制19DEM-数据精度问题(LogDepth)1. 使用对数深度(log depth )算法在GPU中 计算解决单浮点经纬计算问题2. 修改shader ,增加对(logDepth)算法支持3. 修改C++端代码,实现对shader数据的输入20DEM-数据结构优化1.当下使用CPU端数据通过接口的方式传递给GPU,速度慢2. 使用Instance 方式降低Vertex Buffer 的大小,优化渲染系统21DEM-GPU缓冲区优化1. 使用Vertex Buffer Object / Index Buffer Object  / Instance  方式优化渲染系统2. 修改绘制接口,使用DrawElementsInstanceBaseInstance方式提升系统性能内存池与对象池22瓦片生成优化/对象池1. 相机移动过程中会频繁的建立与释放瓦片,对CPU有较大的消耗2. 引入内存池,避免频繁的内存申请与释放,降低CPU时间3. 改造智能指针对象,对象释放通知到内存管理,回收对象内存23改造任务系统支持对象池1. 任务系统是一个公用模块,被多个模块使用,避免频繁的内存操作,引起的内存碎片2. 实现对象池,并应用到任务模块法线计算24法线计算1. 修改现有顶点结构,增加法线支持2. 修改shader,增加法线顶点输入,使用平行光光照模型3. 修改绘制流程,支持光照计算,使用探照灯作为光源输入25顶点法线计算/共享法线计算1. 增加数据结构保存顶点数据被多个面共享的次数2. 计算面法线,并累加到顶点法线中3. 根据顶点被面共享的次数平均法线计算4. 修改流程,按需更新法线数据26法线数据压缩1. 法线数据使用3 * float 数据存储,大大的增加了系统的数据2. 实现算法,将3 * float 数据压缩成4字节数据3. 改造绘制代码,支持压缩数据输入27GPU中计算产生法线数据(去掉CPU中计算)1. 引擎支持 Geometry Shader 阶段2. 编写 Geometry Shader,实现法线计算系统功能优化28重构CPU拾取流程1. 当下的拾取流程,只支撑二维数据拾取,无法准群的拾取三维数据2. Terrain中增加拾取接口,输入射线,输出拾取到顶点数据29绘制拾取结果1. 增加一个绘制点的方法,实现绘制代码2. 修改shader,增加logdepth3. 调试代码,花费了很多时间排查错误,最总排查到是因为uniform参数笔误写错造成。30任务系统完善,避免任务队列无线膨胀1. 任务系统中,没有限制队列的大小,生产者的能力远大于消费者的能力,造成任务队列膨胀2. 处理办法,限制生产者的生产能力,而不是限制任务队列大小(这种方式会造成业务逻辑异常复杂)3. 使用sleep休眠方式(这种方式是严重错误的)31如何避免瓦片数据抖动1. 产生瓦片抖动的原因 ? 分裂算法与回退算法中间没有过度2. 引入过度流程,避免内存抖动,参数因子是一个重要的数据,需要谨慎使用3. 有必要结合瓦片自身数据动态计算参数因子32瓦片数据管理-fepk文件格式支持-全球数据加载1. 支持fepk文件格式,增加fepk读取组件,适配fepk文件2. fepk管理数据方式:一般情况选择全球前10级别作为基础级别,因数据量不大(1G)左右,后续以8级作为基础级别,全球19级别数据被划分为 2^8 * 2^7(512 * 256)个块。每个块中包含了256 * 256 张小瓦片33fepk高程数据读取 34高程分裂处理当瓦片没有高程数据,那么子节点以及其他后代节点该如何共享父节点的数据35lesson-734-高程瓦片分裂处理(2)-算法实现高程数据分裂算法实现实现对高程数据的切分,并对特殊数据进行处理36高程瓦片分裂处理(3)-问题排查 37高程瓦片分裂处理(4)-(后代节点更新问题)当一个瓦片高程数据更新后,他的儿子节点,孙子节点...该如何处理?38瓦片视锥裁剪错误高程数据更新后,没有技术计算瓦片包围盒信息,造成包围盒错误,进而引视锥计算错误39http支持1.引入三方库 Libcurl2.http类封装,支持http读取数据40fepk.server使用 生成三维地球41改造四叉树-统一使用经纬度输入42地形网络生成算法重构 43引入球体坐标系 44使用球体坐标改造瓦片 45多图层(加载标签数据) 课时截图:镜头拉近后,显示细节数据加载矢量SHP国界线数据:加载矢量三维白膜数据截图高程数据加载点云数据 加载倾斜摄影数据 

16,467

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧