📄 memmap.cpp
字号:
// MemMap.cpp: implementation of the CMemMap class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MemMap.h"
#define MUTEX_NAME _T("2682BA67-0B61-4c07-9391-A7B75722A510")
#define MUTEX_WAIT INFINITE
#define UPPER_BOUNDARY(x) ( (x + MMF_PAGESIZE - 1) & ~(MMF_PAGESIZE - 1) )
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMemMap::CMemMap() : m_hMappedFiles(0),
m_pMappedViews(0),
m_lpContainerName(0),
m_lpUniqueContainerNames(0),
m_uPageCount(0),
m_lpReturnBuffer(0),
m_lpDataBuffer(0)
{
/***************************************************
* Nothing special, just set the variables
***************************************************/
}
CMemMap::~CMemMap()
{
/***************************************************
* Close all handles and delete internal buffers
***************************************************/
// Close all the handles
Close();
EndProtect();
// clean up any used internal memory
if ( m_lpUniqueContainerNames ) {
for (UINT i=0; i<m_uPageCount; i++)
delete [] m_lpUniqueContainerNames[i];
delete [] m_lpUniqueContainerNames;
delete [] m_lpContainerName;
}
if ( m_lpReturnBuffer )
delete [] m_lpReturnBuffer;
if ( m_lpDataBuffer )
delete [] m_lpDataBuffer;
}
DWORD CMemMap::Create(LPCTSTR szMappedName, DWORD dwWaitTime, ULONG ulMappedSize)
{
/********************************************************************
* Create a single page to check if already exists
* Grow the arrays to either ulMappedSize or m_uPageCount
********************************************************************/
ASSERT ( szMappedName );
m_uPageCount = 1;
UINT uActualSize = 1;
// make a copy of the container name
LPTSTR szName = (TCHAR*)szMappedName;
m_lpContainerName = new TCHAR [_tcslen(szName) + 1];
_tcscpy(m_lpContainerName,szName);
CreateContainerNames(0,1);
// intitialize the arrays
m_hMappedFiles = new HANDLE [m_uPageCount];
m_pMappedViews = new LPVOID [m_uPageCount];
// read or set the first page
DWORD dwError = MapFiles(0,1);
if ( dwError == ERROR_ALREADY_EXISTS ) {
// get the pagecount from the file and grow
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
LPBYTE lpDebugView = (LPBYTE)m_pMappedViews[0]; // enable the watch view
// get the page count flag
memcpy(&uActualSize,lpBytePos,4);
}
else if ( dwError == ERROR_SUCCESS ) {
// align the size to the MMF_SEGMENTSIZE boundary
if ( ulMappedSize <= 0) ulMappedSize = 1;
ulMappedSize = UPPER_BOUNDARY(ulMappedSize);
// set the page count
uActualSize = ulMappedSize / MMF_PAGESIZE;
// set the flags and page count
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
LPBYTE lpDebugView = (LPBYTE)m_pMappedViews[0]; // enable the watch view
memcpy(lpBytePos,&uActualSize,4);
}
else
return dwError;
// grow the arrays to the new size
Grow(uActualSize - m_uPageCount);
return InitProtect(szMappedName,dwWaitTime);
}
BOOL CMemMap::Close()
{
/********************************************************************
* Unmap and close all the handles
********************************************************************/
ASSERT(m_uPageCount >= 0);
ASSERT(m_pMappedViews);
ASSERT(m_hMappedFiles);
for (UINT i=0;i<m_uPageCount; i++ ) {
if ( UnmapViewOfFile(m_pMappedViews[i]) ) {
if ( CloseHandle(m_hMappedFiles[i]) ) {
m_pMappedViews[i] = 0;
m_hMappedFiles[i] = 0;
}
else
return FALSE;
}
else
return FALSE;
}
m_pMappedViews = 0;
m_hMappedFiles = 0;
return TRUE;
}
DWORD CMemMap::MapFiles(UINT uStart, UINT uEnd)
{
/******************************************************************
* Fill each array member with a handle
******************************************************************/
DWORD dwError;
for (UINT i=uStart; i<uEnd; i++) {
// Create file mapping which can contain MMF_PAGESIZE bytes
m_hMappedFiles[i] = CreateFileMapping(
(HANDLE)0xFFFFFFFF, // system paging file
NULL, // security attributes
PAGE_READWRITE, // protection
0, // high-order DWORD of size
MMF_PAGESIZE, // low-order DWORD of size
m_lpUniqueContainerNames[i]); // name
dwError = GetLastError();
if ( ! m_hMappedFiles[i] ) {
TRACE ( _T("Failed to create File Mapping") );
return 1;
}
else {
m_pMappedViews[i] = MapViewOfFile(m_hMappedFiles[i],FILE_MAP_ALL_ACCESS,0,0,0);
if ( ! m_pMappedViews[i] ) {
TRACE ( _T("Failed to MapViewOfFile") );
return 1;
}
}
if ( dwError != ERROR_ALREADY_EXISTS ) {
// set the memory to unallocated
memset(m_pMappedViews[i], 0xFF, MMF_PAGESIZE);
}
}
return dwError;
}
VOID CMemMap::CreateContainerNames(UINT uStart, UINT uEnd)
{
/********************************************************************
* Create or append to an array of unique page names
********************************************************************/
ASSERT ( m_lpContainerName );
try
{
// create a new array and copy the existing data
LPTSTR *newNames = new LPTSTR [uEnd];
memset(newNames, 0, uEnd);
for (UINT i=0; i<uStart; i++)
newNames[i] = m_lpUniqueContainerNames[i];
// append the new names
for (i=uStart; i<uEnd; i++) {
newNames[i] = new TCHAR [_tcslen(m_lpContainerName) + 6];
_tcscpy(newNames[i],m_lpContainerName);
// append a unique number
TCHAR tmp[6];
if (i < 10)
_stprintf(tmp,_T("_000%i"),i);
else if (i < 100)
_stprintf(tmp,_T("_00%d"),i);
else if (i < 1000)
_stprintf(tmp,_T("_0%d"),i);
else
_stprintf(tmp,_T("_%d"),i);
_tcscat(newNames[i],tmp);
}
if ( m_lpUniqueContainerNames )
delete [] m_lpUniqueContainerNames;
m_lpUniqueContainerNames = newNames;
}
catch (...)
{
TRACE ( _T("Failed to CreateContainerNames") );
}
}
DWORD CMemMap::Grow(UINT uGrowBy)
{
/********************************************************************
* Extend all the arrays and init the appended handles
********************************************************************/
if ( uGrowBy <= 0 )
return ERROR_SUCCESS;
DWORD dwError = 0;
try {
// set the variables and pointers
UINT newSize = m_uPageCount + uGrowBy;
HANDLE *newMappedFiles;
LPVOID *newMappedViews;
// create the arrays
newMappedFiles = new HANDLE [newSize];
newMappedViews = new LPVOID [newSize];
memset(newMappedFiles ,0, newSize);
memset(newMappedViews ,0, newSize);
// copy the existing data
for (UINT i=0; i<m_uPageCount; i++) {
newMappedFiles[i] = m_hMappedFiles[i];
newMappedViews[i] = m_pMappedViews[i];
}
// delete the origional
delete [] m_hMappedFiles;
delete [] m_pMappedViews;
// replace the origional
m_hMappedFiles = newMappedFiles;
m_pMappedViews = newMappedViews;
// append to the name array
CreateContainerNames(m_uPageCount, newSize);
// initialize the new slots
dwError = MapFiles(m_uPageCount, newSize);
if ( dwError != ERROR_SUCCESS && dwError != ERROR_ALREADY_EXISTS )
return dwError;
// set the new size
m_uPageCount = newSize;
// edit the flags and size
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0];
memcpy(lpBytePos,&m_uPageCount,4);
}
catch (...)
{
TRACE ( _T("Failed to Grow") );
}
return dwError;
}
VOID CMemMap::Shrink(UINT uShrinkBy)
{
/********************************************************************
* Close the unused handles and reduce the arrays
********************************************************************/
if ( uShrinkBy <= 0 )
return;
try
{
// set the variables and pointers
UINT newSize = m_uPageCount - uShrinkBy;
HANDLE *newMappedFiles;
LPVOID *newMappedViews;
// create the arrays
newMappedFiles = new HANDLE [newSize];
newMappedViews = new LPVOID [newSize];
memset(newMappedFiles ,0, newSize);
memset(newMappedViews ,0, newSize);
// copy the existing data
for (UINT i=0; i<newSize; i++) {
newMappedFiles[i] = m_hMappedFiles[i];
newMappedViews[i] = m_pMappedViews[i];
}
// close the unused handles
for (i; i<m_uPageCount; i++) {
if ( UnmapViewOfFile(m_pMappedViews[i]) ) {
if ( CloseHandle(m_hMappedFiles[i]) ) {
m_pMappedViews[i] = 0;
m_hMappedFiles[i] = 0;
}
}
}
// delete the origional
delete [] m_hMappedFiles;
delete [] m_pMappedViews;
// replace the origional
m_hMappedFiles = newMappedFiles;
m_pMappedViews = newMappedViews;
// set the new size
m_uPageCount = newSize;
// edit the flags and size
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0];
memcpy(lpBytePos,&m_uPageCount,4);
}
catch (...)
{
TRACE ( _T("Failed to Shrink") );
}
}
VOID CMemMap::CheckForNewPages()
{
/****************************************************
* This must be called before any public read/write
* code executes
* Check the page size in the file against allocated size
* increase as necessary
****************************************************/
ASSERT ( m_pMappedViews );
ASSERT ( m_lpUniqueContainerNames );
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
UINT uPageCount;
// Get the actual number of pages
memcpy(&uPageCount,lpBytePos,4);
// Check if page count changed
if ( uPageCount > m_uPageCount ) {
// open the pages
Grow(m_uPageCount - uPageCount);
}
else if ( uPageCount > m_uPageCount ) {
// a vacuum was performed close unused handles
Shrink(uPageCount - m_uPageCount);
Vacuum();
}
else {
// Do nothing
}
}
VOID CMemMap::Vacuum()
{
/****************************************************
* Remove any pages not being used
* Remove unique names for those pages
****************************************************/
ASSERT ( m_pMappedViews );
ASSERT ( m_lpUniqueContainerNames );
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
UINT uPage = 0;
// First byte is reserved for flags
lpBytePos += 4;
UINT i;
// seek to the end of the data
while ( 1 ) {
i = GetID(uPage,lpBytePos);
if ( i == 0xFFFFFFFF || i == 0xFFFFFF00 )
// unused memory
break;
NextID(&uPage,&lpBytePos);
}
// check if a vacuum is warrented
if ( uPage == m_uPageCount-1 )
return;
// keep at least 1 page
if ( uPage == 0 )
uPage = 1;
// close unused handles
for (i=uPage; i<m_uPageCount; i++ ) {
if ( UnmapViewOfFile(m_pMappedViews[i]) ) {
if ( CloseHandle(m_hMappedFiles[i]) ) {
m_pMappedViews[i] = 0;
m_hMappedFiles[i] = 0;
}
else return;
}
else return;
}
// delete unused names
for (i=uPage; i<m_uPageCount; i++)
delete [] m_lpUniqueContainerNames[i];
// set the new page count
m_uPageCount = uPage;
// edit the flags and size
lpBytePos = (LPBYTE)m_pMappedViews[0];
memcpy(lpBytePos,&m_uPageCount,4);
}
BOOL CMemMap::FindID(UINT uId, UINT *uPage, LPBYTE *lpOffset)
{
/****************************************************
* Search through the pages for the id
* if found return the memory location in lpOffset
* and insert the page number into uPage
* else return the insertion point
****************************************************/
ASSERT( m_pMappedViews );
ASSERT( uPage );
ASSERT( lpOffset );
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
UINT iBuf = 0;
// Track the position
UINT uCurPage = *uPage;
// skip the flags
lpBytePos += 4;
// Start the loop
while ( 1 ) {
// Get the id
iBuf = GetID(uCurPage,lpBytePos);
// check if eof or unallocated
if (iBuf == 0xFFFFFFFF || iBuf == 0xFFFFFF00) {
// unused memory (insertion point)
*uPage = uCurPage;
*lpOffset = lpBytePos;
return FALSE;
}
// iBuf now holds the id, compare it
if (iBuf == uId) {
// string found
*uPage = uCurPage;
*lpOffset = lpBytePos;
return TRUE;
}
NextID(&uCurPage,&lpBytePos);
lpBytePos = lpBytePos;
*uPage = uCurPage;
}
// We shouldn't be here
ASSERT( 1 );
*uPage = 0;
*lpOffset = 0;
return FALSE;
}
VOID CMemMap::Write(UINT *uPage, LPBYTE *lpOffset, UINT uLen, LPVOID lpIn)
{
/*******************************************************
* Write uLen of lpIn to lpOffset
* lpOffset may be spanned
* lpIn MUST be sequecial
* Set lpOffset and uPage to the end of the string
* if data is spanned check to add a new page
*******************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -