www.pudn.com > MemFile.rar > MEMMAP.CPP


/* 
Module : MEMMAP.CPP 
Purpose: Implementation for an MFC class to wrap memory mapped files 
Created: PJN / MEMMAP/1 / 19-03-1997 
History: PJN / 31-3-1998  1) Class now avoids trying to lock the mutex if only read access is required 
                          2) User now has the option of specifying whether a file should be mapped with  
                             A Null terminator at the end. Can prove helpful when you want to use some 
                             of the "C" runtime functions on the pointer returned. 
         PJN / 20-4-1998  1) Now uses GetFileSize SDK call instead of GetFileInformationByHandle as a 
                             more "reliable" way to determine file length. 
                          2) Included TRACE statements to call GetLastError in all places where  
                             SDK functions fail 
         PJN / 29-5-1998  1) Mapping a file now has the option of making it named or not. 
         PJN / 22-10-1998 1) Fixed a bug in a number of calls to CreateMappingName when the classes were  
                             being used to share memory. 
                          2) Tidy up of the demo app including: 
                             a) Made the amount of text being shared a constant of MAX_EDIT_TEXT instead 
                             of hardcoding it to 20 everywhere in the sample. 
                             b) Changed where the timer is being created to OnInitDialog 
                             c) Tidied up the initialisation sequence in OnInitDialog 
                             d) Now using _tcscpy instead of _tcsncpy to ensure array is null terminated 
                             e) Fixed resource.h which was causing the resources to fail to compile 
                             f) Removed unnecessary symbols from resource.h 
                             g) Optimized the way the OnTimer code works to only update the text when it 
                             has changed in the MMF. This means that you can type continuously into the 
                             edit control. 
                          3) New documentation in the form of a HTML file. 
                          4) Sample now ships as standard with VC 5 workspace files 
 
 
 
 
Copyright (c) 1997 - 1998 by PJ Naughter.   
All rights reserved. 
 
*/ 
 
/////////////////////////////////  Includes  ////////////////////////////////// 
#include "stdafx.h" 
#include "memmap.h" 
 
 
 
///////////////////////////////// Implementation ////////////////////////////// 
 
 
 
IMPLEMENT_DYNAMIC(CMemMapFile, CObject) 
 
 
CMemMapFile::CMemMapFile() 
{ 
  //Initialise variables to sane values 
  m_hFile = INVALID_HANDLE_VALUE; 
  m_hMapping = NULL; 
  m_bReadOnly = TRUE; 
  m_bAppendNull = FALSE; 
  m_lpData = NULL; 
  m_bOpen = FALSE; 
  m_hMutex = NULL; 
  m_dwLength = 0; 
} 
 
CMemMapFile::~CMemMapFile() 
{ 
  UnMap(); 
} 
 
BOOL CMemMapFile::MapFile(const CString& sFilename, BOOL bReadOnly, DWORD dwShareMode, BOOL bAppendNull, BOOL bNamed) 
{ 
  //Work out the file access flags 
  m_bReadOnly = bReadOnly; 
	DWORD dwDesiredFileAccess = GENERIC_READ; 
	if (!m_bReadOnly) 
		dwDesiredFileAccess |= GENERIC_WRITE; 
 
  //store away the append Null flag 
  m_bAppendNull = bAppendNull; 
 
  //Open the real file on the file system 
  m_hFile = CreateFile(sFilename, dwDesiredFileAccess, dwShareMode, NULL,  
                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
  if (m_hFile == INVALID_HANDLE_VALUE) 
  { 
    TRACE("Failed in call to CreateFile, GetLastError returned %d\n", GetLastError()); 
    UnMap(); 
    return FALSE; 
  } 
 
	// Get the size of the file we are mapping 
  DWORD dwFileSizeHigh=0; 
  m_dwLength = GetFileSize(m_hFile, &dwFileSizeHigh); 
  if (m_dwLength == 0xFFFFFFFF) 
  { 
    //There was an error calling GetFileSize 
    TRACE("Failed in call to GetFileSize, GetLastError returned %d\n", GetLastError()); 
    UnMap(); 
    return FALSE; 
  } 
 
  //Fail if file is greater than 4GB in size 
  if (dwFileSizeHigh) 
  { 
    //There was an error calling GetFileSize 
    TRACE("File size is greater than 4GB, Memory mapping the file will not work until we support Win64\n"); 
    UnMap(); 
    return FALSE; 
  } 
 
  //Do the actual mapping 
  m_sMappingName = CreateMappingName(sFilename, bNamed); 
  return MapHandle(m_hFile); 
} 
 
BOOL CMemMapFile::MapMemory(const CString& sName, DWORD dwBytes, BOOL bReadOnly) 
{ 
  m_dwLength = dwBytes; 
  m_bReadOnly = bReadOnly; 
  m_bAppendNull = FALSE; 
  m_sMappingName = CreateMappingName(sName, TRUE); 
  return MapHandle((HANDLE)0xFFFFFFFF); 
} 
 
BOOL CMemMapFile::MapExistingMemory(const CString& sName, DWORD dwBytes, BOOL bReadOnly) 
{ 
  m_dwLength = dwBytes; 
  m_bReadOnly = bReadOnly; 
 
  DWORD dwDesiredAccess = (!bReadOnly) ? FILE_MAP_WRITE : FILE_MAP_READ; 
  m_sMappingName = CreateMappingName(sName, TRUE); 
  m_hMapping = OpenFileMapping(dwDesiredAccess,	0, m_sMappingName); 
  if (m_hMapping == NULL) 
  { 
    TRACE("Failed in call to OpenFileMapping, GetLastError returned %d\n", GetLastError()); 
    UnMap(); 
    return FALSE; 
  } 
 
  //Map the view 
  m_lpData = MapViewOfFile(m_hMapping, dwDesiredAccess, 0, 0, m_dwLength); 
 
  //Create the mutex to sync access 
  m_hMutex = CreateMutex(NULL, FALSE, CreateMutexName()); 
 
  return (m_lpData != NULL); 
} 
 
BOOL CMemMapFile::MapHandle(HANDLE hHandle) 
{ 
  //Create the file mapping object 
  DWORD flProtect = (!m_bReadOnly) ? PAGE_READWRITE : PAGE_READONLY; 
 
  //work out the length of the file mapping to create 
  DWORD dwLength = m_dwLength; 
  if (m_bAppendNull) 
    dwLength += 2; 
 
  m_hMapping = ::CreateFileMapping(hHandle, NULL, flProtect, 0, dwLength, m_sMappingName); 
  if (m_hMapping == NULL) 
  { 
    TRACE("Failed in call to CreateFileMapping, GetLastError returned %d\n", GetLastError()); 
    UnMap(); 
    return FALSE; 
  } 
 
  //Map the view 
	DWORD dwDesiredAccess = (!m_bReadOnly) ? FILE_MAP_WRITE : FILE_MAP_READ; 
  m_lpData = MapViewOfFile(m_hMapping, dwDesiredAccess, 0, 0, 0); 
 
  //null terminare if asked to do so 
  if (m_bAppendNull && m_lpData) 
  { 
    //use two Nulls just incase the data as viewed as an array of wide characters 
    BYTE* lpData = (BYTE*) m_lpData; 
    lpData[m_dwLength] = 0; 
    lpData[m_dwLength+1] = 0; 
  } 
 
  //Create the mutex to sync access 
  m_hMutex = CreateMutex(NULL, FALSE, CreateMutexName()); 
 
  return (m_lpData != NULL); 
} 
 
LPVOID CMemMapFile::Open(DWORD dwTimeout) 
{ 
  if (m_lpData == NULL) 
    return NULL; 
 
  if (m_bReadOnly) 
  { 
    m_bOpen = TRUE; 
	  return m_lpData; 
  } 
  else 
  { 
    //Synchronise access to the MMF using the named mutex 
	  DWORD dwResult = WaitForSingleObject(m_hMutex, dwTimeout); 
 
	  if (dwResult == WAIT_OBJECT_0) 
	  { 
		  m_bOpen = TRUE; 
		  return m_lpData; 
	  } 
 
    return NULL; 
  } 
} 
 
BOOL CMemMapFile::Close() 
{ 
  //Release our interest in this MMF 
  if (!m_bOpen) 
    return FALSE; 
 
  m_bOpen = FALSE; 
  ReleaseMutex(m_hMutex); 
   
  return TRUE; 
} 
 
BOOL CMemMapFile::Flush() 
{ 
  if (m_lpData == NULL) 
		return FALSE; 
 
  return FlushViewOfFile(m_lpData, 0); 
} 
 
CString CMemMapFile::GetMappingName() const 
{ 
  return m_sMappingName; 
} 
 
CString CMemMapFile::CreateMutexName() const 
{ 
  return m_sMappingName + _T("MUTEX"); 
} 
 
void CMemMapFile::UnMap() 
{ 
  //Close any views which may be open 
	Close(); 
 
  //unmap the view 
	if (m_lpData != NULL) 
	{ 
		FlushViewOfFile(m_lpData, 0); 
		UnmapViewOfFile(m_lpData); 
		m_lpData = NULL; 
	} 
 
  //remove the file mapping 
	if (m_hMapping != NULL) 
	{ 
		CloseHandle(m_hMapping); 
		m_hMapping = NULL; 
	} 
 
  //close the file system file if its open 
	if (m_hFile != INVALID_HANDLE_VALUE) 
	{ 
		CloseHandle(m_hFile); 
		m_hFile = INVALID_HANDLE_VALUE; 
	} 
 
  //Close the mutex we have been using 
	if (m_hMutex != NULL) 
	{ 
		CloseHandle(m_hMutex); 
		m_hMutex = NULL; 
	} 
 
  //Reset the remaining member variables 
  m_bReadOnly = TRUE; 
  m_sMappingName = _T(""); 
  m_dwLength = 0; 
} 
 
CString CMemMapFile::CreateMappingName(const CString& sName, BOOL bNamed) 
{ 
  CString rVal; 
  if (bNamed) 
  { 
    rVal = sName; 
 
    //Replace all '\' by '_' 
    for (int i=0; i