⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memmap.cpp

📁 memory map file class for C++ builder
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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 + -