// ============================================================================ // Copyright (C) 2001-2011 by Jozef Starosczyk // ixen@copyhandler.com // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU Library General Public License // (version 2) as published by the Free Software Foundation; // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this program; if not, write to the // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // ============================================================================ /// @file TSharedMemory.cpp /// @date 2011/05/03 /// @brief Contains implementation of shared memory handling classes. // ============================================================================ #include "stdafx.h" #include "TSharedMemory.h" #include #include "ErrorCodes.h" BEGIN_CHCORE_NAMESPACE #define MUTEX_SUFFIX _T("_Mutex") class TMutexLock { public: TMutexLock(HANDLE hMutex) : m_hMutex(hMutex) { if(m_hMutex) { DWORD dwRes = WaitForSingleObject(hMutex, 10000); if(dwRes != WAIT_OBJECT_0) THROW_CORE_EXCEPTION(eErr_MutexTimedOut); } } ~TMutexLock() { if(m_hMutex) ReleaseMutex(m_hMutex); } private: HANDLE m_hMutex; }; /////////////////////////////////////////////////////////////////////////////////////// // TSharedMemory class TSharedMemory::TSharedMemory() : m_hFileMapping(NULL), m_pMappedMemory(NULL), m_hMutex(NULL), m_stSize(0) { } TSharedMemory::~TSharedMemory() { Close(); } void TSharedMemory::Create(const wchar_t* pszName, size_t stSize) { if(!pszName || pszName[0] == _T('\0') || stSize == 0) THROW_CORE_EXCEPTION(eErr_InvalidArgument); Close(); try { std::wstring wstrMutexName = pszName; wstrMutexName += MUTEX_SUFFIX; SECURITY_DESCRIPTOR secDesc; if(!InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION)) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); SECURITY_ATTRIBUTES secAttr; secAttr.nLength = sizeof(secAttr); secAttr.bInheritHandle = FALSE; secAttr.lpSecurityDescriptor = &secDesc; if(!SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, 0, FALSE)) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); m_hMutex = ::CreateMutex(&secAttr, FALSE, wstrMutexName.c_str()); if(!m_hMutex) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); m_hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, &secAttr, PAGE_READWRITE, 0, boost::numeric_cast(stSize + sizeof(size_t)), pszName); if(!m_hFileMapping) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); else if(GetLastError() == ERROR_ALREADY_EXISTS) THROW_CORE_EXCEPTION(eErr_SharedMemoryAlreadyExists); // shared memory already exists - cannot guarantee that the size is correct // Get a pointer to the file-mapped shared memory. m_pMappedMemory = (BYTE*)MapViewOfFile(m_hFileMapping, FILE_MAP_WRITE, 0, 0, 0); if(!m_pMappedMemory) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); } catch(...) { Close(); throw; } TMutexLock lock(m_hMutex); m_stSize = stSize + sizeof(size_t); *(size_t*)m_pMappedMemory = sizeof(size_t); // no data inside (set just in case) } void TSharedMemory::Create(const wchar_t* pszName, const TString& wstrData) { Create(pszName, (const BYTE*)(const wchar_t*)wstrData, (wstrData.GetLength() + 1) * sizeof(wchar_t)); } void TSharedMemory::Create(const wchar_t* pszName, const BYTE* pbyData, size_t stSize) { Create(pszName, stSize); TMutexLock lock(m_hMutex); *(size_t*)m_pMappedMemory = stSize; memcpy(m_pMappedMemory + sizeof(size_t), pbyData, stSize); } void TSharedMemory::Open(const wchar_t* pszName) { Close(); try { m_hFileMapping = OpenFileMapping(FILE_MAP_READ, FALSE, pszName); if(!m_hFileMapping) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); // Get a pointer to the file-mapped shared memory. m_pMappedMemory = (BYTE*)MapViewOfFile(m_hFileMapping, FILE_MAP_READ, 0, 0, 0); if(!m_pMappedMemory) THROW_CORE_EXCEPTION(eErr_CannotOpenSharedMemory); } catch(...) { Close(); throw; } TMutexLock lock(m_hMutex); m_stSize = *(size_t*)m_pMappedMemory + sizeof(size_t); } void TSharedMemory::Close() throw() { try { if(m_hMutex) { CloseHandle(m_hMutex); m_hMutex = NULL; } if(m_pMappedMemory) { UnmapViewOfFile(m_pMappedMemory); m_pMappedMemory = NULL; } // Close the process's handle to the file-mapping object. if(m_hFileMapping) { CloseHandle(m_hFileMapping); m_hFileMapping = NULL; } } catch(...) { } } void TSharedMemory::Read(TString& wstrData) const { if(!m_hFileMapping || !m_pMappedMemory || m_stSize <= sizeof(size_t)) THROW_CORE_EXCEPTION(eErr_SharedMemoryNotOpen); TMutexLock lock(m_hMutex); size_t stByteSize = *(size_t*)m_pMappedMemory; if((stByteSize % 2) != 0) THROW_CORE_EXCEPTION(eErr_SharedMemoryInvalidFormat); const wchar_t* pszRealData = (const wchar_t*)(m_pMappedMemory + sizeof(size_t)); size_t stCharCount = stByteSize / 2; if(pszRealData[stCharCount - 1] != _T('\0')) THROW_CORE_EXCEPTION(eErr_SharedMemoryInvalidFormat); wstrData = pszRealData; } void TSharedMemory::Write(const TString& wstrData) { Write((const BYTE*)(const wchar_t*)wstrData, (wstrData.GetLength() + 1) * sizeof(wchar_t)); } void TSharedMemory::Write(const BYTE* pbyData, size_t stSize) { if(stSize + sizeof(size_t) > m_stSize) THROW_CORE_EXCEPTION(eErr_BoundsExceeded); TMutexLock lock(m_hMutex); *(size_t*)m_pMappedMemory = stSize; memcpy(m_pMappedMemory + sizeof(size_t), pbyData, stSize); } const BYTE* TSharedMemory::GetData() const { if(!m_hFileMapping || !m_pMappedMemory || m_stSize <= sizeof(size_t)) return NULL; return (BYTE*)m_pMappedMemory + sizeof(size_t); } BYTE* TSharedMemory::GetData() { if(!m_hFileMapping || !m_pMappedMemory || m_stSize <= sizeof(size_t)) return NULL; return (BYTE*)m_pMappedMemory + sizeof(size_t); } size_t TSharedMemory::GetSharedMemorySize() const { if(!m_hFileMapping || !m_pMappedMemory) return 0; return m_stSize; } size_t TSharedMemory::GetDataSize() const { if(!m_hFileMapping || !m_pMappedMemory || m_stSize <= sizeof(size_t)) return 0; TMutexLock lock(m_hMutex); return *(size_t*)m_pMappedMemory; } END_CHCORE_NAMESPACE