Files
core/Common/ShareMemArray.h
Alexander.Trofimov beb64a6efa utf8 -> utf8 with BOM
2016-06-23 19:23:34 +03:00

346 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2016
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
/***************************************************************
CShareMemArray
шаблон класса для работы с именованной
Shared-памятью. Реализаваны загрузка массива
из памяти и сохранение в память.
***************************************************************/
#pragma once
#pragma warning( disable : 4996 4244) // No CRT-secure warning
#include <atlcoll.h>
#include "ASCUtils.h" // CSyncAccess class definition
#define AVS_USER_NAME_LEN 1024
// Статус хранилища (ошибка, уже создано, новое)
enum TSMAStatus {SMAS_ERROR, SMAS_ALREADYEXISTS, SMAS_NEW};
// Хранилище
template <typename STOR_TYPE>
class CShareMemArray
{
protected:
HANDLE m_hAccessMutex; // Мьютекс для безопасного доступа к Shared-Memory
HANDLE m_hMapFile; // Хендл на map таблицы
STOR_TYPE *m_pArray; // Указатель на массив
LONG64 m_nSize; // Размер таблицы
CString m_sMutexName; // Имя мьютекса
CString m_sMapName; // Имя маппа
TSMAStatus m_sStatus;
protected:
// Читаем из памяти
bool ReadFromSharedMem(LONG64 nIndex, STOR_TYPE &nValue)
{
if (NULL == m_pArray)
{
m_sStatus = SMAS_ERROR;
return false;
}
__try
{
STOR_TYPE *pTable = (STOR_TYPE *) (((BYTE *) m_pArray) + sizeof(LONG64)); // sizeof(LONG64) - размер таблицы
nValue = pTable[nIndex];
}
__except(EXCEPTION_IN_PAGE_ERROR == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Failed to read from the view.
ATLTRACE2("CIndexerStorage::ReadFromSharedMem()\n");
return false;
}
return true;
}
// Пишем в память
bool WriteToSharedMem(LONG64 nIndex, STOR_TYPE aValue)
{
if (NULL == m_pArray)
{
m_sStatus = SMAS_ERROR;
return false;
}
__try
{
STOR_TYPE *pTable = (STOR_TYPE *) (((BYTE *) m_pArray) + sizeof(LONG64)); // sizeof(LONG64) - размер таблицы
pTable[nIndex] = aValue;
}
__except(EXCEPTION_IN_PAGE_ERROR == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Failed to read from the view.
ATLTRACE2("Error CIndexerStorage::WriteToSharedMem(#i)\n", nIndex);
return false;
}
return true;
}
// Загрузка таблицы индексов из SharedMemory
bool SaveTable_unsync(CAtlArray<STOR_TYPE> &aTable)
{
if ((NULL == m_pArray) || (NULL == m_hMapFile))
{
m_sStatus = SMAS_ERROR;
return false; // Защита от дурака
}
bool bRes = true;
// Защита от дурака
LONG64 nCopyCount = (m_nSize <= (LONG64) aTable.GetCount()) ? m_nSize : aTable.GetCount();
// Сохраняем размер таблицы
Size_unsync(m_nSize);
// копируем из памяти в массив (safe)
for (LONG64 nIndex = 0; nIndex < nCopyCount; nIndex++)
{
bRes &= WriteToSharedMem (nIndex, aTable[nIndex]);
}
return bRes;
}
// Сохранение таблицы индексов из SharedMemory
bool LoadTable_unsync(CAtlArray<STOR_TYPE> &aTable)
{
if ((NULL == m_pArray) || (NULL == m_hMapFile))
{
m_sStatus = SMAS_ERROR;
return false; // Защита от дурака
}
aTable.RemoveAll();
// Определяем размер
m_nSize = Size_unsync();
STOR_TYPE nValue;
// копируем из памяти в массив
for (DWORD nIndex = 0; nIndex < m_nSize; nIndex++)
{
if (ReadFromSharedMem(nIndex, nValue))
{
// Добавляем в таблицу
aTable.Add(nValue);
}
}
return true;
}
// Размер
LONG64 Size_unsync()
{
LONG64 nValue = -1;
if (NULL == m_pArray)
{
m_sStatus = SMAS_ERROR;
return nValue;
}
__try
{
LONG64 *pSize = (LONG64 *) m_pArray;
nValue = *pSize;
}
__except(EXCEPTION_IN_PAGE_ERROR == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Failed to read from the view.
ATLTRACE2("CIndexerStorage::Size_unsync()\n");
return -1;
}
return nValue;
}
void Size_unsync(LONG64 aSize)
{
if (NULL == m_pArray)
{
m_sStatus = SMAS_ERROR;
return;
}
__try
{
LONG64 *pSize = (LONG64*) m_pArray; // sizeof(LONG64) - размер таблицы
*pSize = aSize;
}
__except(EXCEPTION_IN_PAGE_ERROR == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Failed to read from the view.
ATLTRACE2("Error CIndexerStorage::Size_unsync(LONG64 aSize)\n");
}
}
public:
// aSize - размер таблицы индексации (кол-во полусекунд),
// Id - дополнительный идектификатор, чтоб можно было создавать много сторейджей для одного файла
CShareMemArray(CString &aFileName, LONG64 aSize, DWORD aId = ISID_DEFAULT):
m_hMapFile(NULL), m_nSize(aSize), m_pArray(NULL), m_sStatus(SMAS_ERROR)
{
// "Вытаскиваем" имя файла
TCHAR aDrive[_MAX_DRIVE];
TCHAR aDir[_MAX_DIR];
TCHAR aFName[_MAX_FNAME];
TCHAR aExt[_MAX_EXT];
_tsplitpath (aFileName.GetBuffer(), aDrive, aDir, aFName, aExt);
//_wsplitpath_s (aFileName.GetBuffer(), aDrive, _MAX_DRIVE, aDir, _MAX_DIR, aFName, _MAX_FNAME, aExt, _MAX_EXT);
// Дополнительно формируем уникальные символы для этого пути, чтобы включить в имя файла
DWORD dwPathID = 0;
TCHAR tcPathIDItem = 0;
// Подсчитываем контрольную сумму для пути
for (int i = 0; i < (int) _tcslen(aDir); i++)
{
tcPathIDItem ^= aDir[i];
dwPathID ^= dwPathID << 1;
dwPathID += (DWORD) tcPathIDItem;
}
// Подсчитываем контрольную сумму для расширения
DWORD dwExtID = 0;
TCHAR tcExtIDItem = 0;
for (int i = 0; i < (int) _tcslen(aExt); i++)
{
tcExtIDItem ^= aExt[i];
dwExtID ^= dwExtID << 1;
dwExtID += (DWORD) tcExtIDItem;
}
// Формируем имя мутекса и мапа
// Этот код не работает если зашло два пользователя и каждый запускает свою копию приложения.
// Фича в именовании мьютекса.
// В начале имени мьютекса должно стоять "Global\"
// ШульгаИван: "Global\" не проходит на Win7, если прога запущена не под админом
m_sMutexName.Format(_T("Local\\avs_mutex%u_%s_%06x_%06I64x_%06x"), aId, aFName, dwPathID, aSize, dwExtID);
m_sMapName.Format(_T("Local\\avs_storage%u_%s_%06x_%06I64x_%06x"), aId, aFName, dwPathID, aSize, dwExtID);
// добавляем имя юзера
TCHAR pBufferUserName[AVS_USER_NAME_LEN];
DWORD dwBufferUserNameLen = AVS_USER_NAME_LEN;
GetUserName(pBufferUserName, &dwBufferUserNameLen);
CString strUserName(pBufferUserName, dwBufferUserNameLen);
m_sMutexName += strUserName;
m_sMapName += strUserName;
// Создаем мьютекс
m_hAccessMutex = CreateMutex(NULL, FALSE, m_sMutexName.GetBuffer());
// Далее все делаем "под мутексом" :)
CSynchAccess oAccess = m_hAccessMutex;
// Создаем мап
ATLTRACE2("CShareMemArray()::CShareMemArray(): m_nSize = %d\n", m_nSize);
ULARGE_INTEGER nMappingSize;
nMappingSize.QuadPart = m_nSize * sizeof(STOR_TYPE) + sizeof(LONG64);
m_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, nMappingSize.HighPart, nMappingSize.LowPart, m_sMapName.GetBuffer());
if (NULL == m_hMapFile)
{
// Ошибка
ATLTRACE2("CShareMemArray::CShareMemArray():CreateFileMapping() FAILS (0x%x)!\n", GetLastError());
m_sStatus = SMAS_ERROR;
}
else
{
// Все ок!
m_sStatus = (GetLastError() == ERROR_ALREADY_EXISTS) ? SMAS_ALREADYEXISTS : SMAS_NEW;
ATLTRACE2 (SMAS_ALREADYEXISTS == m_sStatus ? "CShareMemArray: open existing!\n" : "CShareMemArray: create new!\n");
// создаем View of file
m_pArray = (STOR_TYPE *) MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, (SIZE_T) nMappingSize.QuadPart);
if (NULL == m_pArray)
{
// Ошибка
ATLTRACE2("CShareMemArray::CShareMemArray():MapViewOfFile() FAILS (0x%x)!\n", GetLastError());
m_sStatus = SMAS_ERROR;
}
}
}
virtual ~CShareMemArray()
{
if (m_pArray) UnmapViewOfFile(m_pArray); // удаляем view
if (NULL != m_hMapFile) CloseHandle(m_hMapFile); // удаляем мап
if (NULL != m_hAccessMutex) CloseHandle(m_hAccessMutex); // Удаляем мьютекс
}
public:
// Сохранить таблицу в шаред-мемори
bool Save(CAtlArray<STOR_TYPE> &aTable)
{
CSynchAccess oAccess = m_hAccessMutex;
return SaveTable_unsync(aTable);
}
// Загрузить таблицу
bool Load(CAtlArray<STOR_TYPE> &aTable)
{
CSynchAccess oAccess = m_hAccessMutex;
return LoadTable_unsync(aTable);
}
// Размер получение
LONG64 Size()
{
CSynchAccess oAccess = m_hAccessMutex;
return Size_unsync();
}
/*void Size(LONG64 aSize)
{
CSynchAccess oAccess = m_hAccessMutex;
Size_unsync(aSize);
}*/
// Получение статуса
TSMAStatus Status(void) const
{
CSynchAccess oAccess = m_hAccessMutex;
return m_sStatus;
}
};