Sometimes you need to share some values across several processes. There are some ways, provided by system, but there is no simple way to share simple values like DWORDs or strings. And of course, synchronization is also required in this case.
DWORD
I was inspired by PJ Naughter's solution, but I wanted more. I wanted structured shared memory, with variables, synchronization and wait functionality within it.
Variables are shared within an unnamed memory file. This 'file' (or better, block of memory) is allocated in the page file. It is not possible to create growable file of this type, but I did not require it. The internal structure of this memory is as follows:
DWORD DWORD ValueHeader[0] value 0 ValueHeader[1] value 1 .............. ValueHeader[n] value n
The first DWORD is the number of values within memory. The second DWORD is the memory size; it includes these two DWORDs too. ValueHeader is a structure defined as:
ValueHeader
typedef struct _tagValueHeader { WCHAR wszValueName[VAR_NAME_LENGTH]; DWORD dwLength; } ValueHeader;
Member wszValueName is value name, dwLength is length in bytes of the value, which follows this structure. As you can see, the actual value is stored as several bytes. There is no type checking of the value's type. It is not allowed access the variable directly. Instead of that, the class provides several methods to access values. It allows synchronized access, and it is possible to wait for value or memory changes.
wszValueName
dwLength
Construction and destructions CSharedMemory ~CSharedMemory General methods GetMemName IsCreated GetMemSize AmIFirst GetLastError Access control methods SetSdMem GetSdMem SetSdSem GetSdSem SetSaEvent Value management methods AddValue AddDwordValue DeleteValue ExistValue GetVariablesCount GetValueInfo Value access methods SetValue GetValue Wait methods WaitForMemChange WaitForValueChange WaitForMultipleValuesChanges Interlocked* methods InterlockedIncrement InterlockedDecrement InterlockedExchange InterlockedTestExchange InterlockedCompareExchange InterlockedExchangeAdd Direct memory access methods Read Write DEBUG methods AssertValid Dump
CSharedMemory(TCHAR *szName, DWORD dwSize = DEF_SHARED_SIZE, PINITMEMORY InitMemoryProcedure = NULL, void *pInitProcParam = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL);
Constructor for the class. It creates shared memory named szName, of dwSize< size. When you want initialize memory at the same place as you declare it, you can define an initializer function, defined as:
szName
dwSize<
initializer function
void InitMemory(CSharedMemory *pMem, void *pInitProcParam)
And you can pass its address to the constructor. This solution allows you write shorter code like:
... CSharedMemory sh_mem("MemoryName",1024,InitMemory); ...
'Initialize' means, for example to add some variables. If you need to pass your own initialization value, then you can specify it in the pInitProcParam parameter. If you don't provide this value at the construction time, then constructor will pass NULL to your initializer function. lpsaAttributes defines access control rights and security attributes of the memory mapped file, semaphore and events created inside the CSharedMemory object. For more information see SECURITY_ATTRIBUTES.
pInitProcParam
NULL
lpsaAttributes
CSharedMemory
~CSharedMemory();
Destructor for the class. It frees all allocated resources.
CString GetMemName(void);
Returns name of the shared memory.
BOOL IsCreated(void);
Returns TRUE if memory was successfully created.
TRUE
DWORD GetMemSize(void);
Returns size of memory.
BOOL AmIFirst(void);
Returns TRUE, if caller was first, who created memory.
DWORD GetLastError(void);
Returns a Win32 error code that describes the best last error inside a call made to the object.
BOOL SetSdMem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
This method sets the security descriptor for memory mapped file. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve error code. See also SetKernelObjectSecurity().
FALSE
BOOL GetSdMem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
This method gets the security descriptor of the memory mapped file. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve error code. See also GetKernelObjectSecurity().
BOOL SetSdSem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
This method sets the security descriptor of the semaphore, which synchronizes access to shared memory. If it fails, returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code. See also SetKernelObjectSecurity().
BOOL GetSdSem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
This method gets security descriptor of the semaphore, which synchronizes access to shared memory. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code. See also GetKernelObjectSecurity().
BOOL SetSaEvent(LPSECURITY_ATTRIBUTES lpsaAttributes);
This method sets internal variable to security attributes, which are used to protect internal events object. These events are used to 'wait' for changes in the memory or variable. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve error code.
BOOL AddValue(const TCHAR *szName, DWORD size, void *pDefaultData = NULL);
This method adds new value named szName. It creates a new entry within memory and reserves space of size for new value. If it fails, returns FALSE, otherwise TRUE. You can use the last parameter to set its value after it is created. Call CSharedMemory::GetLastError() to retrieve the error code.
size
BOOL AddDwordValue(const TCHAR *szName, DWORD dwDefault = 0);
Method adds new DWORD value named szName. It creates a new entry within memory and reserves space of size for new value. If it fails, it returns FALSE, otherwise TRUE. You can use last parameter to set its value after it is created. Call CSharedMemory::GetLastError() to retrieve the error code.
BOOL DeleteValue(TCHAR *szName);
This method deletes the value named szName from memory, it frees used space and freed memory is filled with zeros. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve error code.
BOOL ExistValue(TCHAR *szName);
This method returns TRUE, if variable szName exists within memory. If it fails, returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code (when constructor failed, this method returns FALSE, but CSharedMemory::GetLastError() returns a different error code).
DWORD GetVariablesCount(void);
This method returns the number of values stored in the memory. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code.
BOOL GetValueInfo(DWORD dwIndex, ValueHeader *pVarInfo);
This method copies value information of the format ValueHeader to memory pointed by pVarInfo. If it fails, returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code.
pVarInfo
BOOL SetValue(TCHAR *szName, void *bData, DWORD dwLength);
This method sets the variable named szName to value pointed to by bData. Length of the data at address bData is passed as the last parameter. It can be less then allocated length within shared memory. In this case the rest of the allocated buffer is filled with zeros. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code.
bData
BOOL GetValue(TCHAR *szName, void *bData, LPDWORD dwLength);
This method retrieves thevalue of the variable szName. Data is stored at address bData. The length stored at bData is returned in dwLength. It is possible to pass in bData NULL, then the method returns in dwLength the required buffer length. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError()to retrieve the error code.
DWORD WaitForMemChange(DWORD dwMilliseconds = INFINITE);
This method waits for any change in the structure of the shared memory. 'Change' means add or delete a variable. When you do not use variables, but direct access functions, then you can use this method to wait for the changes. For direct access see CSharedMemory::Read() or CSharedMemory::Write(). If it fails, it returns WAIT_FAILED value, see also WaitForSingleObject() .
direct access functions
WAIT_FAILED
DWORD WaitForValueChange(TCHAR *szName, DWORD dwMilliseconds = INFINITE);
This methods waits for changes of value. It also returns, when a variable is deleted. If it fails, itreturns WAIT_FAILED value, see also WaitForSingleObject().
DWORD CSharedMemory::WaitForMultipleValuesChanges(CStringArray & str,BOOL bWaitForAll , DWORD dwMilliseconds =INFINITE );
This methods waits for changes of values. It also returns when variables are deleted. You can choose to wait for change of one or several values. If it fails, it returns WAIT_FAILED value, see also WaitForMultipleObject().
All Interlocked* functions are described in the MSDN. Methods of CSharedMemory work the same way, except they return TRUE/FALSE as an indicator of success, and the return value of emulated functions is returned through a pointer (usually the last optional parameter).
BOOL InterlockedIncrement(TCHAR *szName, LPLONG plNewVal = NULL);
See also InterlockedIncrement().
BOOL InterlockedDecrement(TCHAR *szName, LPLONG plNewVal = NULL);
See also InterlockedDecrement().
BOOL InterlockedExchange(TCHAR *szTargetName, LONG lNewVal, LPLONG plPrevValue = NULL);
See also InterlockedExchange().
BOOL InterlockedTestExchange(TCHAR *szTargetName, LONG lOldValue, LONG lNewValue, LPLONG plPrevValue = NULL);
See also InterlockedTestExchange().
BOOL InterlockedCompareExchange(TCHAR *szTargetName, LONG lExchange, LONG lComperand, LPLONG plIntiVal = NULL);
See also InterlockedCompareExchange().
BOOL InterlockedExchangeAdd(TCHAR *szTargetName, LONG lIncrement, LPLONG plIntiVal = NULL);
See also InterlockedExchangeAdd().
BOOL Read(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
This method reads dwLength bytes from offset dwOffset within memory. It is allowed to access shared memory this way only when it contains no variables. Method writes data at the address pbData. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code.
dwOffset
pbData
BOOL Write(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
Method writes dwLength bytes from pbData at the offset dwOffeset within the shared memory. It is allowed to access shared memory this way only when it contains no variables. If it fails, it returns FALSE, otherwise TRUE. Call CSharedMemory::GetLastError() to retrieve the error code.
dwOffeset
void AssertValid(void);
This methof performs a validity check on this object by checking its internal state.
void Dump(CDumpContext & dc);
Dumps the contents of shared memory to a CDumpContext object.
CDumpContext
I have provided a simple demo program to demonstrate usage of the CSharedMemory class. A shared block of the memory exists within the system until the last instance of the CSharedMemory class is destroyed. CSharedMemory is UNICODE enabled; it will work in UNICODE or ANSI programs. It is possible to share the same memory from both types of programs. CSharedMemory uses simple diagnostic functions from Helpers.h and Helpers.cpp
The demo program provides an interface to the many methods of CSharedMemory, and you can use more instances of it to play with CSharedMemory and see how it works. It also demonstrates usage of the class.
AddDwordValue()
WaitForMultipleValuesChanges()
AddValue()
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here
General News Suggestion Question Bug Answer Joke Rant Admin
Math Primers for Programmers