Click here to Skip to main content
Click here to Skip to main content

A Simple Wrapper for Sharing Data Structures Between Processes

By , 17 Sep 2001
Rate this:
Please Sign up or sign in to vote.

Shared Memory in action!

What this Article Is

A common task in advanced Windows programming is to share data between two or more processes. There have been several articles written on the subject, but many were too complex for what I needed. What I needed was a very simple means to share data between several running instances of my application. Since the interaction between these instances is rather complex, I wanted to handle synchronization, etc. on my own rather than find a framework which supported the level of synchronization I wanted.

What this Article Is Not

I said, this article is about a simple way to share memory between multiple processes. The code presented makes no effort to synchronize read and write access to the data block. Likewise, all clients connecting to the shared memory are given full access to the shared memory. While adding a security model to the class is almost trivial, I decided not to in an effort to keep the code simple.

Introducing CSharedStruct

In this article, memory is shared via a class I created called CSharedStruct. This class encapsulates the shared memory region. The code is relatively simple, and rather short, as seen below:

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CSharedStruct_H__86467BA6_5AFA_11D3_863D_00A0244A9CA7__INCLUDED_)
#define AFX_CSharedStruct_H__86467BA6_5AFA_11D3_863D_00A0244A9CA7__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define SHARED_NAME_SIZE 256

template <class StructType>
class CSharedStruct
{
private:
   HANDLE m_hFileMapping;
   char   m_hSharedName[SHARED_NAME_SIZE];
   DWORD  m_dwMaxDataSize;
   StructType *m_pvData;

   BOOL m_bCreated;

public:
   CSharedStruct();
   VOID Release();
   BOOL Acquire(char *Name);

   StructType *operator->();
};


template <class StructType>
StructType *CSharedStruct<StructType>::operator->()
{
   return m_pvData;
}

template <class StructType>
CSharedStruct<StructType>::CSharedStruct()
{
   m_hFileMapping = NULL;
}

template <class StructType>
VOID CSharedStruct<StructType>::Release()
{
   if (m_pvData)
   {
      UnmapViewOfFile(m_pvData);
   }

   if (m_hFileMapping)
   {
      CloseHandle(m_hFileMapping);
   }
}

template <class StructType>
BOOL CSharedStruct<StructType>::Acquire(char *Name)
{
   m_dwMaxDataSize = 0;
   m_hFileMapping = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, 
              PAGE_READWRITE, 0, sizeof(StructType), Name);

   if (m_hFileMapping == NULL)
   {
      return FALSE;
   }

   m_dwMaxDataSize = sizeof(StructType);
   strncpy(m_hSharedName, Name, SHARED_NAME_SIZE - 1);

   m_pvData = (StructType *) MapViewOfFile( m_hFileMapping, 
                 FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

   if (m_pvData == NULL)
   {
      CloseHandle(m_hFileMapping);
      return FALSE;
   }

   return TRUE;
}

#endif

The first thing to notice is that, this is a template based class. While template syntax might make the include file a little harder to read, it makes the code written to access the shared data much cleaner. To create a shared memory object, first we declare the structure we want to share, then we wrap it in a CSharedStruct template, like:

typedef struct _MyData
{
   int x;
   char text[256];
} MyData;

CSharedStruct<MyData> m_SharedData("SharedDataName");

The text string passed into the constructor identifies the shared memory object to use. So, if we want to share multiple memory buffers, we need to give each one a unique name. If we want to access a shared memory buffer in another application, we must pass the same name to the constructor.

//m_SharedData1 and m_SharedData2 actually 'point' to the same data
CSharedStruct<MyData> m_SharedData1("Alpha");
CSharedStruct<MyData> m_SharedData2("Alpha");

//m_SharedData3, on the other hand, 'points' to a new block of shared memory
CSharedStruct<MyData> m_SharedData3("Beta");

Remember that these names need to be unique across all processes. If you write myprogram.exe which uses a shared structure named "Shared", and I write myotherprogram.exe using a CSharedStruct with the same name, we'll end up pointing to the same data! As such, I suggest using the guidgen.exe program in the Platform SDK to create a unique GUID to append to any names you use, just to be safe.

Also realize that these shared memory sections can be seen by other processes. If someone learns the name of the shared memory section (say by using SysInternals' HandleEx program), they can look at your shared data. If this bothers you, encrypt your data before placing it in a shared memory section and implement security attributes for the file mapping.

If for some reason, you want to use the default constructor, you have to "initialize" the shared memory buffer by explicitly calling Acquire(char *Name). I'm not sure why you'd want to do this, but it's there in case the need arises.

Finally, to access the data members of the structure, use the -> operator, which has been overloaded to point to the shared memory our template class envelopes. An example shows how easy this is to do:

m_SharedData.x = 255;
strcpy(m_SharedData->text, "Hello Shared World!");

How does this work?

The CSharedStruct class uses the memory-mapped file operations built in Windows. It's really a rather simple API call:

m_hFileMapping = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, 
        PAGE_READWRITE, 0, sizeof(StructType), Name);

CreateFileMapping returns a handle to a file mapping object and is usually used to map files on disk to user-mode addressable virtual addresses. However, if INVALID_HANDLE_VALUE is passed as the file handle to map, the Operating System uses a portion of the page file to back-up the virtual address it returns. The next parameter, NULL in this case, points to a Security Attributes object. If you are concerned about the security of the data you share, something besides NULL should be passed in here. PAGE_READWRITE grants us read/write access to the shared memory. Again, this can be changed if security is required and some clients only need read-only access to the data. The next two parameters are the size of the shared memory as a 64-bit number split into two 32-bit integers. Unless you're sharing more than 2GB of data, dwMaximumSizeHigh will always be zero. Finally, we pass in the name of the Shared Memory object we want to access. If you're sharing data between a user mode application and a Windows NT/2000 service, make sure you prefix your name with "Global" if Terminal Services are installed, otherwise your shared structures will not point to the same data.

The Sample Application

The included sample uses CSharedStruct to share a simple data structure. While the code presented above does not require MFC, the sample was built in MFC for simplicity. It's very straight forward, with a little code of interest other than the declaration of the CSharedStruct object. OnSet() and OnGet() simply synchronize the shared memory and the user interface.

To test the application, you need to run two instances. I'd suggest running one normally (e.g. not debugging), then debug the second instance if you want to see how the code works. Enter in values for the Number and Text fields in one instance, and press 'Set', then switch to the other instance, and press 'Get'... That's about as exciting as the sample gets!

Updates, Errata

  • Sept. 17th, 2001

    Updated example and source to fix two bugs in the Release() method which lead to potential resource leaks. Thanks to Stanley He for pointing this out.

  • Sept. 18th, 2001

    Updated example and source to support Service/User process interaction. Previously, if the service created the file-mapping object first, then user processes could not access it. The simple solution was to modify the ACL of the file-mapping object, giving everyone the access rights needed. More robust security concerns are left as an exercise for the reader. The demo application has been updated, and now includes a simple service (made with Joerg Koenig's CNTService class wizard).

License

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

About the Author

Ryan Schneider
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionLicense? Pinmemberignac13-Jan-14 7:39 
Questiona bug in CSharedStruct<StructType>::CSharedStruct(char *Name) Pinmemberwenhm5-May-13 23:09 
QuestionCross-Platform Version of CSharedStruct Pinmemberwonus8-Mar-12 4:11 
AnswerRe: Cross-Platform Version of CSharedStruct Pinmemberstelip19-Jun-12 11:38 
GeneralRe: Cross-Platform Version of CSharedStruct [modified] Pinmemberwonus24-Jun-12 11:31 
QuestionLicense? PinmemberMember 809235618-Jul-11 1:10 
QuestionHow can we implement into C# PinmemberMukeshKorat9-Mar-09 10:50 
AnswerRe: How can we implement into C# Pinmemberwonus8-Mar-12 4:01 
GeneralOdd about how the size works PinmemberMike Morrow22-Jul-08 21:51 
GeneralI did this 10 years ago... Pinmemberdlesko22-Jun-08 20:31 
GeneralBEWARE: BUGGY!!! Pinmembers_dimi7-Sep-07 4:52 
GeneralRe: It's won't work on Windows Vista PinmemberSandipShahane23-Nov-06 8:54 
GeneralRe: It's won't work on Windows Vista Pinmembers_dimi7-Sep-07 6:26 
GeneralSmall fix... Pinmemberkhb7-Mar-06 4:50 
GeneralRe: Small fix... PinmemberTarun Ray5-Nov-09 20:18 
GeneralRe: Small fix... PinmemberTarun Ray5-Nov-09 20:21 
GeneralWon't run... Pinmemberthe_augy16-Feb-06 18:03 
AnswerRe: Won't run... PinmemberBartosz Bien5-Jun-06 21:25 
Generalmm.h library in C for sahred memory Pinmembermora2629-Oct-05 14:25 
GeneralCalling the Constructor PinmemberAndreas Schönle30-Sep-05 0:50 
GeneralRe: Calling the Constructor PinmemberAndreas Schönle30-Sep-05 0:58 
GeneralRe: Calling the Constructor Pinmemberehaerim27-Jun-07 17:37 
GeneralAn invalid handle was specified. Pinmembercats819927-Sep-05 6:26 
GeneralAccess Data from client PinmemberImBatman23-Jun-05 22:54 
GeneralRe: Access Data from client PinmemberImBatman23-Jun-05 23:15 
GeneralTo pass an array of structures PinmemberTarun Karela9-Aug-04 5:19 
GeneralRe: To pass an array of structures PinmemberMessnerEW22-Nov-04 23:18 
GeneralRe: To pass an array of structures PinmemberMessnerEW22-Nov-04 23:20 
GeneralGood stuff ...made it so well for me Pinmemberdilipm@danlawinc.com2-Mar-04 22:00 
GeneralRe: Good stuff ...made it so well for me Pinmembermatro28-Sep-04 12:55 
QuestionHow to share objects between Processes PinmemberAsif Khattak16-Jan-04 2:10 
AnswerRe: How to share objects between Processes PinmemberEl Viejo Kike8-Mar-04 3:20 
GeneralRe: How to share objects between Processes PinmemberMember 36796614-Oct-10 0:30 
Questionbug? PinmemberMichael Bridges27-Oct-03 9:34 
AnswerRe: bug? PinmemberNguyen Huu Hoa25-Nov-03 17:28 
QuestionHow on Unix Pinmembervagrawal7-Aug-03 2:21 
GeneralDynamic memory Pinmemberadithya1-Jan-02 21:55 
GeneralProtecting the data from corruption through Mutex. PinmemberAnonymous19-Oct-01 1:14 
GeneralShared objects PinmemberAnonymous8-Oct-01 6:22 
GeneralCrash PinmemberTodd Smith4-Oct-01 16:13 
GeneralRe: Crash Pinmemberrhubarb81-Oct-03 11:11 
GeneralRe: Crash Pinmemberosr27-Feb-04 5:50 
GeneralRe: Crash Pinmembersilygose28-Apr-05 5:45 
GeneralRe: Crash Pinmembersirnoname18-May-06 4:30 
GeneralPlanned Update PinmemberRyan Schneider17-Sep-01 7:47 
GeneralRe: Planned Update PinmemberRyan Schneider19-Sep-01 4:12 
Questionwhere are the attached samples? PinmemberSaeed10-Sep-01 15:35 
AnswerRe: where are the attached samples? PinmemberRyan Schneider11-Sep-01 10:12 
GeneralRe: where are the attached samples? PinmemberSaeed11-Sep-01 19:51 
GeneralRe: where are the attached samples? PinmemberRyan Schneider12-Sep-01 4:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 18 Sep 2001
Article Copyright 2001 by Ryan Schneider
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid