Shared memory segment in a C++ Class Library (DLL) for .NET applications
|
|
Environment: Visual C++ (VS 2008) .NET
(Show Win32 C++ Example)
Applications sometimes need to share memory for interprocess communication on the
same computer. This
example provides a managed code C++ .NET Class Library that can be consumed from .NET applications
for interprocess communications. This example is coded in VS 2008,
and a
VC6 Win32 example can be found here. The following example
defines a .SHAREDMEMORY data segment that can be shared across multiple process
on the same computer. This is accomplished by setting the _Xml buffer from an access method, and retrieving the XML document buffer from another application by calling
the same access method. A module scoped named Mutex is used to gain a lock the
shared memory segment so that each process consuming the DLL is granted
exclusive read/write access.
Using the #pragma data_seg (".SHAREDMEMORY")
you must make sure that the variables
declared in the segment are initialized when they are declared.
During construction of the CSharedMemory class the variables are set to whatever
values you require to begin using the object. The shared memory segment will
only be initialized when when the first instance of the object is created because
_Initialized will be set to true when the next application creates an instance
of the object.
While there are other ways to share memory between applications like Memory Mapped
Files, simply sharing a common storage buffer is sufficient for many applications.
An XML document (or whatever you want) can be used to transfer data back and forth
between processes. This example stores string data but the access methods
and buffer can be defined to store BYTE data if you just want to store raw data.
To download this project
click here (VS 2008 SharedMemory.zip) or you can download the compiled dll
class library (32K buffer size) by
clicking here (Compiled Class Library DLL).
First the C++ header file that defines the shared memory buffer and access methods
for getting and setting the data. An important item to note is the
XML_BUFFER_SIZE
definition, and in this case it is set at 32K. This needs to be defined large enough
to accomodate the largest document that you might pass between applications. Shared
memory segments must be defined when declared to insure a block of memory is available
for your applications, so you may need to set this value to your needs
before compiling the dll.
#pragma once
#include < string.h >
using namespace System::Threading;
using namespace System;
using namespace System::Runtime::InteropServices;
namespace SharedMemory {
#define XML_BUFFER_SIZE 32769 // 32K + 1 buffer size
#pragma data_seg (".SHAREDMEMORY")
bool _Initialized = false;
char _Xml[XML_BUFFER_SIZE] = {0};
#pragma data_seg()
#pragma comment(linker,"/SECTION:.SHAREDMEMORY,RWS")
public ref class CSharedMemory
{
protected:
static Mutex^ _Lock = gcnew Mutex(false, "CSharedMemory-19B33A40-CEDA-477e-A688-504C105256E6");
public:
CSharedMemory();
bool SetData(String^ data, bool autoLock);
String ^ GetData(bool clearOnRead, bool autoLock);
void Lock();
void UnLock();
const int BufferSize();
};
}
Now the CPP file containing the implementation of this class. Data is shared
using the GetData() and
SetData() access methods. You can explicitly set a lock on the memory segment by
calling the .Lock() method prior to calling GetData() or SetData(). Once you
get/set data you must call the .Unlock() method if you called the .Lock()
method. You can also set autoLock parameter = true when calling these access
methods and the lock will be supplied automatically during the call.
Important: If you explicitly call .Lock() and .Unlock() before and after using
the access methods you must set the autoLock parameter = false.
Type |
Method/Property |
Description |
Method |
.SetData() |
Sets data to the shared memory segment. (String) |
Method |
.GetData() |
Gets data from shared memory segment (String) |
Method |
.Lock() |
Locks the shared memory segment for exclusive access. |
Method |
.UnLock() |
Releases the lock on the shared memory segment. |
Method |
.BufferSize() |
Gets size of buffer as defined |
#include "SharedMemory.h"
namespace SharedMemory {
CSharedMemory::CSharedMemory()
{
if(!_Initialized)
{
_Lock->WaitOne();
memset(_Xml, 0, XML_BUFFER_SIZE);
_Initialized = true;
_Lock->ReleaseMutex();
}
}
bool CSharedMemory::SetData(String^ data, bool autoLock)
{
bool result = true;
if(autoLock)
{
_Lock->WaitOne();
}
memset(_Xml, 0, XML_BUFFER_SIZE);
if(data->Length < XML_BUFFER_SIZE)
{
memcpy((char*)_Xml, (char*)Marshal::StringToHGlobalAnsi(data).ToPointer(), data->Length);
}
else
{
result = false;
}
if(autoLock)
{
_Lock->ReleaseMutex();
}
return result;
}
String^ CSharedMemory::GetData(bool clearOnRead, bool autoLock)
{
if(autoLock)
{
_Lock->WaitOne();
}
String^ data = gcnew String(_Xml);
if(clearOnRead)
{
memset(_Xml, 0, XML_BUFFER_SIZE);
}
if(autoLock)
{
_Lock->ReleaseMutex();
}
return data;
}
void CSharedMemory::Lock()
{
_Lock->WaitOne();
}
void CSharedMemory::UnLock()
{
_Lock->ReleaseMutex();
}
const int CSharedMemory::BufferSize()
{
return (const int)XML_BUFFER_SIZE - 1;
}
}
To use this class simply add a reference to the SharedMemory.Dll and use the SharedMemory
namespace. To set data use the SetData("Your Data") method and to retrieve
document use the String GetData() method from your application that uses the Class
Library.
Important: You should declare the CSharedMemory object at a module or global scope in
your application so that the global shared memory segment will persist while your application is running.
Following is a simple C# Form that demonstrates how to access the shared memory segment.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SharedMemory;
namespace SharedMemTest
{
public partial class Form1 : Form
{
CSharedMemory m_Mem = new CSharedMemory();
private void SetMem()
{
m_Mem.Lock();
m_Mem.SetData("Test Data 1234", false);
m_Mem.UnLock();
}
private string GetMem()
{
m_Mem.Lock();
string data = m_Mem.GetData(false, false);
m_Mem.UnLock();
return data;
}
}
}
To download this project
click here (VS 2008 SharedMemory.zip) or you can download the compiled dll class
library (32K buffer size) by
clicking here (Compiled Class Library DLL).
Hope this helps!