Sdílení paměti mezi aplikacemi (MFC a C++)

Pokud tvoříte aplikaci, která bývá v systému spuštěna vždy ve více instancích, tak je někdy potřeba, aby si tyto aplikace mohly mezi sebou vyměňovat data nebo nějaká data sdílet. Ve WinAPI je pro toto hned několik funkcí, které si nyní popíšeme.

Vytvoření sdílené paměti

První věc, kterou musíme provést, je získání handle na naši paměť. K tomu slouží funkce CreateFileMapping, která se sice běžně používá pro paměťově mapované soubory, ale umožňuje i práci s pamětí. Zde je její definice:

HANDLE CreateFileMapping(
  HANDLE hFile,                                     //Handle souboru k mapování
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,	//Bezpečnostní nastavení
  DWORD flProtect,     			//Typ přístupu
  DWORD dwMaximumSizeHigh,   	//Velikost paměti - HIGH
  DWORD dwMaximumSizeLow,    	//Velikost paměti - LOW
  LPCTSTR lpName             	//Jméno naší paměti
);

//Příklad na volání
HANDLE hMapping
hMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,
 PAGE_READWRITE | SEC_COMMIT,0,65536,"MojeSdilenaPamet");

if(!hMapping)		//Test na chybu
{
  MessageBox("Nepodařilo se vytvořit paměť!");
  return FALSE;
}

Do prvního parametru funkce se obvykle dosazuje handle souboru, ale to že chceme pracovat s pamětí indikujeme hodnotou 0xFFFFFFFF. Třetí parametr určuje typ přístupu (jen čtení, jen zápis, oboje), čtvrtý a pátý dávají dohromady velikost souboru. High hodnota se však nastavuje pouze pokud bychom chtěli používat velikosti souborů nad 4GB. A poslední parametr určuje pojmenování naší paměti, díky kterému ho rozpoznají i další instance naší aplikace.

V ukázce je tedy příklad na vytvoření 65KB sdílené paměti, která bude zpřístupněna pro čtení i zápis. Další věc, kterou bychom měli udělat, je zjistit, zda je toto první instance aplikace, a pokud ano, tak vytvořenou paměť nějak inicializovat. Zda je to první instance se dá zjistit pomocí hodnoty poslední chyby ERROR_ALREADY_EXISTS. V této ukázce budu sdílenou paměť používat pro uložení řetězců, takže v inicializaci do ní nakopíruji prázdný řetězec.


BOOL First=FALSE;	//Indikuje, zda je toto první instance

if(GetLastError()!=ERROR_ALREADY_EXISTS)	//Zjistit poslední chybu
{
  First=TRUE;
}

Dále potřebujeme získat ukazatel na sdílenou paměť. K tomu slouží funkce MapViewOfFile, která tento ukazatel vrací:

LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,  // Handle pro namapování
  DWORD dwDesiredAccess,      // Typ přístupu
  DWORD dwFileOffsetHigh,     // Offset - HIGH
  DWORD dwFileOffsetLow,      // Offset - LOW
  DWORD dwNumberOfBytesToMap  // Počet bajtů ke sdílení
);

//Příklad

void* ShareMem=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);
if(!m_ShareMem)		//Test na chybu
{
  MessageBox("Nepodařilo se namapovat paměť!");
  return FALSE;
}

if(First)	//Inicializace
{
  strcpy((char*)ShareMem,"");	//Kopíruj prázdný řetězec
}

První parametr je handle, které jsme získali z MapViewOfFile, druhý je opět typ přístupu a tři poslední udávají posunutí od začátku a velikost paměti - stačí nastavit na nulu.

Nyní tedy máte ukazatel na sdílenou paměť a můžete s ní provádět standardní operace. Tato paměť je sdílená, takže všechny instance aplikace mají stejný pointer na paměť.

Ukončení sdílení

Po ukončení programu chceme také ukončít sdílení. Nejdříve je potřeba zavolat funkci UnmapViewOfFile a potom CloseHandle, které se postarají o odpojení a uzavření paměti.

UnmapViewOfFile(ShareMem);
CloseHandle(hMapping);

UPOZORNĚNÍ: Jedná se o archiv článků z let 2003 - 2005, uvedené technologie či postupy již mohou být neaktuální.