Motivation
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 DWORD
s or strings. And
of course, synchronization is also required in this case.
Description of solution
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.
Internal structure
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 DWORD
s too.
ValueHeader
is a structure defined as:
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.
CSharedMemory public class members
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::CSharedMemory
CSharedMemory(TCHAR *szName, DWORD dwSize = DEF_SHARED_SIZE,
PINITMEMORY InitMemoryProcedure = NULL,
void *pInitProcParam = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL);
Remarks
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:
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.
CSharedMemory::~CSharedMemory
~CSharedMemory();
Remarks
Destructor for the class. It frees all allocated resources.
CSharedMemory::GetMemName
CString GetMemName(void);
Remarks
Returns name of the shared memory.
CSharedMemory::IsCreated
BOOL IsCreated(void);
Remarks
Returns TRUE
if memory was successfully created.
CSharedMemory::GetMemSize
DWORD GetMemSize(void);
Remarks
Returns size of memory.
CSharedMemory::AmIFirst
BOOL AmIFirst(void);
Remarks
Returns TRUE
, if caller was first, who created memory.
CSharedMemory::GetLastError
DWORD GetLastError(void);
Remarks
Returns a Win32 error code that describes the best last error
inside a call made to the object.
CSharedMemory::SetSdMem
BOOL SetSdMem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
Remarks
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().
CSharedMemory::GetSdMem
BOOL GetSdMem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
Remarks
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().
CSharedMemory::SetSdSem
BOOL SetSdSem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
Remarks
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().
CSharedMemory::GetSdSem
BOOL GetSdSem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
Remarks
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().
CSharedMemory::SetSaEvent
BOOL SetSaEvent(LPSECURITY_ATTRIBUTES lpsaAttributes);
Remarks:
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.
CSharedMemory::AddValue
BOOL AddValue(const TCHAR *szName, DWORD size, void *pDefaultData = NULL);
Remarks
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.
CSharedMemory::AddDwordValue
BOOL AddDwordValue(const TCHAR *szName, DWORD dwDefault = 0);
Remarks
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.
CSharedMemory::DeleteValue
BOOL DeleteValue(TCHAR *szName);
Remarks
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.
CSharedMemory::ExistValue
BOOL ExistValue(TCHAR *szName);
Remarks
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).
CSharedMemory::GetVariablesCount
DWORD GetVariablesCount(void);
Remarks
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.
CSharedMemory::GetValueInfo
BOOL GetValueInfo(DWORD dwIndex, ValueHeader *pVarInfo);
Remarks
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.
CSharedMemory::SetValue
BOOL SetValue(TCHAR *szName, void *bData, DWORD dwLength);
Remarks
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.
CSharedMemory::GetValue
BOOL GetValue(TCHAR *szName, void *bData, LPDWORD dwLength);
Remarks
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.
CSharedMemory::WaitForMemChange
DWORD WaitForMemChange(DWORD dwMilliseconds = INFINITE);
Remarks
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() .
CSharedMemory::WaitForValueChange
DWORD WaitForValueChange(TCHAR *szName, DWORD dwMilliseconds = INFINITE);
Remarks
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().
CSharedMemory::WaitForMultipleValuesChanges
DWORD CSharedMemory::WaitForMultipleValuesChanges(CStringArray & str,BOOL bWaitForAll , DWORD dwMilliseconds =INFINITE );
Remarks
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).
CSharedMemory::InterlockedIncrement
BOOL InterlockedIncrement(TCHAR *szName, LPLONG plNewVal = NULL);
Remarks
See also InterlockedIncrement().
CSharedMemory::InterlockedDecrement
BOOL InterlockedDecrement(TCHAR *szName, LPLONG plNewVal = NULL);
Remarks
See also InterlockedDecrement().
CSharedMemory::InterlockedExchange
BOOL InterlockedExchange(TCHAR *szTargetName, LONG lNewVal, LPLONG plPrevValue = NULL);
Remarks
See also InterlockedExchange().
CSharedMemory::InterlockedTestExchange
BOOL InterlockedTestExchange(TCHAR *szTargetName, LONG lOldValue, LONG lNewValue, LPLONG plPrevValue = NULL);
Remarks
See also InterlockedTestExchange().
CSharedMemory::InterlockedCompareExchange
BOOL InterlockedCompareExchange(TCHAR *szTargetName, LONG lExchange, LONG lComperand, LPLONG plIntiVal = NULL);
Remarks
See also InterlockedCompareExchange().
CSharedMemory::InterlockedExchangeAdd
BOOL InterlockedExchangeAdd(TCHAR *szTargetName, LONG lIncrement, LPLONG plIntiVal = NULL);
Remarks
See also InterlockedExchangeAdd().
CSharedMemory::Read
BOOL Read(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
Remarks
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.
CSharedMemory::Write
BOOL Write(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
Remarks
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.
CSharedMemory::AssertValid
void AssertValid(void);
Remarks
This methof performs a validity check on this object by
checking its internal state.
CSharedMemory::Dump
void Dump(CDumpContext & dc);
Remarks
Dumps the contents of shared memory to a CDumpContext
object.
Usage
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
Demo program
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.
History
- 4 Dec 2001 - updated source code
- 13 Jan 2001 - updated source code and new constructor
- 24 Sep 2002 - new and improved functionality from Angela Aremu
(
AddDwordValue()
, WaitForMultipleValuesChanges()
and new parameter in AddValue()
)
Credits