Two c++ programs pass variable (share memory?)

I want to run two c++ programs on Microsoft Visual Studio 2005, letting one program generate a data (such as a position (x,y)) and pass it to the other program. Can anyone give me some instructions on that? It'll be great if there is some sample code! Thanks
rxzangAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
itsmeandnobodyelseConnect With a Mentor Commented:
The finally working code is below.

The issues have been:

1. FILE_MAP_ALL_ACCESS is an argument of MapViewOfFile but not for CreateFileMapping

2. FILE_MAP_ALL_ACCESS only works if the hdl was created with PAGE_READWRITE access

3. The written, received members should be volatile so that changes on them were recognized even if the waswritten or wasreceived were inlined.

4. The setxy must not have the condition  'myPtrMem->iswritten() == false'. That was a copy-paste error

5. The getxy must not have the condition  'myPtrMem->isreceived() == false'. That was a copy-paste error

Note, the solution was the ANSI version. If using UNICODE project settings the name of the shared memory must be passed as wide string L'MySharedMem' and the char* turned to wchar_t* (or you call CreateFileMappingA explicitly).

#include <windows.h>
 
struct SharedMemStruct
{
     int x;
     int y;
     volatile bool written;
     volatile bool received;
     SharedMemStruct() : x(0), y(0), written(false), received(false) {}
     void setxy(int xx, int yy) { x = xx; y = yy; written = true; received = false; }
     void getxy(int & xx, int & yy) { xx = x; yy = y; received = true; written = false; }
     bool isreceived() { return received; }
     bool iswritten()  { return written; }
 
};
 
 
class SharedMemory
{
public:
     SharedMemory(const char* szName)
      :  myHdl(INVALID_HANDLE_VALUE) 
      , myPtrMem(NULL)
     {
         myHdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
                    PAGE_READWRITE, 0, sizeof(SharedMemStruct), 
                    szName);
 
          if (myHdl != INVALID_HANDLE_VALUE)
          {             
 
              bool  second = (GetLastError() == ERROR_ALREADY_EXISTS);
 
              myPtrMem = (SharedMemStruct*)MapViewOfFile(
                                  myHdl, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SharedMemStruct));
 
              if (myPtrMem  == NULL) 
              {   
                  int rc = GetLastError();
                  CloseHandle(myHdl);
                  myHdl = 0;
              }
              else if (second == false)
              {
                    memset(myPtrMem, 0, sizeof(SharedMemStruct));
               }
          }
     } 
     ~SharedMemory() 
     {
          if (myPtrMem != NULL)
              UnmapViewOfFile(myPtrMem);
          if (myHdl != INVALID_HANDLE_VALUE)
              CloseHandle(myHdl); 
 
     }
     bool isvalid() { return myHdl != INVALID_HANDLE_VALUE && myPtrMem != NULL;  }
     bool setxy(int x, int y)
     {
          if (myHdl == NULL || myPtrMem == NULL) return false;
          myPtrMem->setxy(x, y);
          return true;
     }
     bool getxy(int& x, int& y)
     {
          if (myHdl == NULL || myPtrMem == NULL) return false;
          myPtrMem->getxy(x, y);
          return true;
     }
    bool waswritten() 
    {  
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->iswritten() == false) return false;
          return true;
    }
    bool wasreceived() 
    {  
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->isreceived() == false) return false;
          return true;
    }
 
private:
     HANDLE myHdl;
     SharedMemStruct * myPtrMem;
          
};
 
// sender.cpp
 
#include "sharedmem.h"
#include <iostream>
using namespace std;
 
int main()
{
     int x = 10;
     int y = 20;
     SharedMemory sm("MySharedMemory");
     if (sm.isvalid())
     {
          sm.setxy(x, y);
     }
     // wait until settings were acknoledged
     while (sm.wasreceived() == false)
     {
          Sleep(1000);   // wait a second
     }
     
     cout << "sender: x = " << x << " y = " << y << endl;
     return 0;
}
 
// receiver.cpp
 
#include "sharedmem.h"
 
#include <iostream>
using namespace std;
 
int main()
{
     SharedMemory sm("MySharedMemory");
     // wait until settings were done
     while (sm.waswritten() == false)
     {
          Sleep(1000);   // wait a second
     }
     int x = 0; 
     int y = 0; 
     sm.getxy(x, y);
     cout << "receiver: x = " << x << " y = " << y << endl;
     return 0;
}

Open in new window

0
 
DanRollinsCommented:
A good answer to this is here:
   Interprocess Communication
   http://www.experts-exchange.com/Programming/Languages/Q_21123509.html
and of course, don't miss the MSDN article:
   Interprocess Communications
   http://msdn.microsoft.com/en-us/library/aa365574(VS.85).aspx
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Look at WM_COPYDATA in help, there is a link to example code on how to use it.
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
itsmeandnobodyelseCommented:
If both programs have a top-level window you could spot the window handle of the target process (e. g. by FindWindow or by enumerating processes or top-level windows) and send a message like

#define WM_USER_SEND_POS  WM_USER + 1234


   PostMessage(hwndTarget, WM_USER_SEND_POS, (WPARAM)xpos, (LPARAM)ypos);

All windows messages greater or equal to WM_USER were reserved fro private messages.

Note, you can't pass pointers to the wparam or lparam argument as pointers were not valid in another process' environment. But if you want to pass mere data than two integers you might pass a handle to global memory where each process can get a valid pointer to by calling GlobalLock.
0
 
itsmeandnobodyelseCommented:
You also could use shared memory e. g. by

      HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE,
            FILE_MAP_ALL_ACCESS,
            PAGE_WRITECOPY,
                                0,
                                1024,
            "MYSHAREDMEM");
 
      LPCTSTR pBuf = (LPTSTR)MapViewOfFile(
            hMapFile,
            FILE_MAP_ALL_ACCESS,
            0,
            0,
            BUF_SIZE);

               // here pbuf could be written to or read from
               // you can map the pbuf to a structure which is
               // an overlay of the shared memory
               MySharedMemStruct * ps = (MySharedMemStruct*)pbuf;
               ps->x = xpos;
               ps->y = ypos;
               UnmapViewOfFile(pbuf);

Note, the shared memory is valid as long as there is an open handle for the named resource. So, the hMapFile should be made a member of an (application) class which should be closed only when the process communication is finished.
0
 
rxzangAuthor Commented:
Hi itsmeandnobodyelse,

Thanks for your reply. I want the shared memory be valid when the process is running. So I should put it into main(), right?

What I need is very simple: program 1 computes x, y and put it into memroy. Program 2 will read x,y from the memory. Could you give me an exact solution, what code I should put into program 1 and what for program 2?

Thanks!
0
 
itsmeandnobodyelseCommented:
>>>> So I should put it into main(), right?

Yes, if using C++ you probably have an application class (a singleton class). Then, you could put it into a member of that class as well:

int main()
{
     MyApp app;
     int rc = app.run();
     return rc;
}

Here either the constructor of MyApp or the run function would do the initialization of the shared memory.

>>>> Could you give me an exact solution, what code I should put into program 1 and what for program 2?
To make the solution robust, you should not make assumptions on which program is first or second. Write code where it doesn't matter which program creates the shared memory and which only opens existing shared memory instead.

To achieve that, you best make a class which handles the shared memory. Then, you either can have a local object of that class in main function or add that as a member to your application class.

struct SharedMemStruct
{
     int x;
     int y;
     bool written;
     bool received;
     SharedMemStruct() : x(0), y(0), written(false), received(false) {}
     void setxy(int xx, int yy) { x = xx; y = yy; written = true; received = false; }
     void getxy(int & xx, int & yy) { xx = x; yy = y; received = true; written = false; }
     bool isreceived() { return received; }
     bool iswritten()  { return written; }
 
};


class SharedMemory
{
public:
     SharedMemory(const char* szName)
      :  myHdl(INVALID_HANDLE_VALUE)
      , myPtrMem(NULL)
     {
          myHdl = CreateFileMapping(INVALID_HANDLE_VALUE,
            FILE_MAP_ALL_ACCESS,
            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
            szName);
          if (myHdl != INVALID_HANDLE_VALUE)
          {            

              bool  second = (GetLastError() == ERROR_ALREADY_EXISTS);
 
              myPtrMem = (SharedMemStruct*)MapViewOfFile(
                                  myHdl, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SharedMemStruct));

              if (myPtrMem  == NULL)
              {          
                  CloseHandle(myHdl);
                  myHdl = 0;
              }
              else if (second == false)
              {
                    memset(myPtrMem, 0, sizeof(SharedMemStruct));
               }
          }
     }
     ~SharedMemory()
     {
          if (myPtrMem != NULL)
              UnMapViewOfFile(myPtrMem);
          if (myHdl != INVALID_HANDLE_VALUE)
              CloseHandle(myHdl);

     }
     bool isvalid() { return myHdl != INVALID_HANDLE_VALUE && myPtrMem != NULL;  }
     bool setxy(int x, int y)
     {
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->iswritten() == false) return false;
          myPtrMem->setxy(x, y);
          return true;
     }
     bool getxy(int& x, int& y)
     {
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->isreceived() == false) return false;
          myPtrMem->getxy(x, y);
          return true;
     }
    bool waswritten()
    {  
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->iswritten() == false) return false;
          return true;
    }
    bool wasreceived()
    {  
          if (myHdl == NULL || myPtrMem == NULL || myPtrMem->isreceived() == false) return false;
          return true;
    }

private:
     HANDLE myHdl;
     SharedMemStruct * myPtrMem;
         
};

// sender.cpp

#include "sharedmem.h"
 
   int main()
   {
         SharedMemory sm("MySharedMemory");
         if (sm.isvalid())
         {
              sm.setxy(10,20);
         }
         // wait until settings were acknoledged
         while (sm.wasreceived() == false)
         {
              Sleep(1000);   // wait a second
         }
         ...
         return 0;
   }

// receiver.cpp

#include "sharedmem.h"
 
   int main()
   {
         SharedMemory sm("MySharedMemory");
         // wait until settings were done
         while (sm.waswritten() == false)
         {
              Sleep(1000);   // wait a second
         }
         int x = 0;
         int y = 0;
         sm.getxy(x, y);
         ...
         return 0;
   }
0
 
rxzangAuthor Commented:
Thanks for the code. I got 2 errors:

sharedmem.h(26) : error C2664: 'CreateFileMappingA' : cannot convert parameter 2 from 'long' to 'LPSECURITY_ATTRIBUTES'

sharedmem.h(49) : error C3861: 'UnMapViewOfFile': identifier not found

0
 
itsmeandnobodyelseCommented:
Try

myHdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
            FILE_MAP_ALL_ACCESS,
            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
            szName);


Should be
 
UnmapViewOfFile(myPtrMem);
0
 
rxzangAuthor Commented:
new error:
'CreateFileMappingW' : function does not take 7 arguments

UnmapViewOfFile seems to work.

Thanks!!!
0
 
rxzangAuthor Commented:
Hi, I tried

myHdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
            szName);

I think you forget to delete FILE_MAP_ALL_ACCESS. I have the following error:
'CreateFileMappingW' : cannot convert parameter 6 from 'const char *' to 'LPCWSTR'

then, I tried
myHdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
            (LPCWSTR) szName);

Now, I can compile this code. But it seems that

SharedMemory sm("MySharedMemory");
         if (sm.isvalid())
                       {
        sm.setxy(10,20);
                       printf("to here\n");
        }

this code did not run setxy(10,20).


0
 
rxzangAuthor Commented:
Do you know why sm.isvalid() is false?
0
 
itsmeandnobodyelseCommented:
>>>> 'CreateFileMappingW' : cannot convert parameter 6 from 'const char *' to 'LPCWSTR'
That is cause your project has UNICODE enabled. Then all char need to be turned to wchar_t.

If you don't need UNICODE I would suggest to switch back to ANSI chars.

Then, the SharedMemory should compile cause CreateFileMapping then was mapped to CreateFileMappingA which takes a const char* (== LPCSTR) as last argument.

If you need UNICODE you may change

     SharedMemory(const char* szName)

to

     SharedMemory(LPCTSTR szName)

and

call it like
         
     SharedMemory sm(_T("MySharedMemory"));

The _T macro either has output "MySharedMemory" for ANSI projects or L"MySharedMemory" for UNICODE projects.

>>>>    then, I tried
>>>>  myHdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
>>>>            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
>>>>            (LPCWSTR) szName);

The cast to  LPCWSTR compiles but doesn't run cause it does not turn the char elements of the szname to wchar_t as needed but only casts the pointer.


0
 
itsmeandnobodyelseCommented:
>>>> Do you know why sm.isvalid() is false?
The CreateFileMapping failed. If you call GetLastError() after CreateFileMapping you will see that the name passed couldn't be resolved to a proper name.
0
 
rxzangAuthor Commented:
Both methods does not work.

For method 1, in Property->General->Character Set, I only found
Use Unicode Character Set
Use Multi-Byte Character Set
Not Set.
I didn't find ANSI...
I tried all 3 options, no one works.

For method2, I changed
 SharedMemory(const char* szName)
to
  SharedMemory(LPCTSTR szName)

and
 SharedMemory sm("MySharedMemory");
to
 SharedMemory sm(_T("MySharedMemory"));
but still doesn't work.
I don't know how to use GetLastError(), but I put it after
 SharedMemory sm(_T("MySharedMemory"));
and didn't get anything printed out.


0
 
itsmeandnobodyelseCommented:
>>>> Use Multi-Byte Character Set

That is the ANSI version which (wrongly) was called 'multibyte' by MS (as it was possible to have a few extended characters which were represented as a sequence of characters rather than a single char).

If you change that settings you need to rebuild all to make it work. Then the CreateFileMapping would map to CreateFileMappingA which takes a const char* (LPCSTR) as last argument and you can/must omit the cast to LPCWSTR which anyhow was wrong as you can't cast a 'multibyte' string to wide char but only convert.

>>>>   SharedMemory sm(_T("MySharedMemory"));

That isn't bad but only if you declared the constructor with SharedMemory(LPCTSTR szName).

Then, it either matches to SharedMemory(LPCSTR szName) if ANSI (multibyte) or  SharedMemory(LPCWSTR szName) if UNICODE (wide char or double-byte).

>>>> I don't know how to use GetLastError()
Put it below call of CreateFileMapping

     SharedMemory(LPCTSTR szName)
      :  myHdl(INVALID_HANDLE_VALUE)
      , myPtrMem(NULL)
     {
          myHdl = CreateFileMapping(INVALID_HANDLE_VALUE,
            FILE_MAP_ALL_ACCESS,
            PAGE_WRITECOPY, 0, sizeof(SharedMemStruct),
            szName);
          if (myHdl != INVALID_HANDLE_VALUE)
          {            

              bool  second = (GetLastError() == ERROR_ALREADY_EXISTS);
 
              myPtrMem = (SharedMemStruct*)MapViewOfFile(
                                  myHdl, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SharedMemStruct));

              if (myPtrMem  == NULL)
              {          
                  CloseHandle(myHdl);
                  myHdl = 0;
              }
              else if (second == false)
              {
                    memset(myPtrMem, 0, sizeof(SharedMemStruct));
               }
           }
           else
           {
                int errcode = GetLastError();
                // if it is a console program do
                cout  <<  "file mapping failed error: " << errcode << endl;
                // if it is a windows program do
                char buf[32] = { 0};
                MessageBox(NULL, "file mapping failed error: ", itoa(errcode, 10, buf), MB_OK);
           }
       }

Note, the error codes can be checked in winerror.h.

0
 
rxzangAuthor Commented:
Hi itsmeandnobodyelse,

if you have time, could you please help to test if the code works on your machine? I'm using windows xp and ms visual studio 2005. I could not make it work (I tried all possible solutions). It seems the errorcode is 5. Thanks.

0
 
itsmeandnobodyelseCommented:
>>>> It seems the errorcode is 5.
That is 'access denied'.

>>>> if you have time, could you please help to test if the code works on your machine?
I'll find time on week-end. I also could post you own working code maybe tomorrow.

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
To repeat myself
Look at WM_COPYDATA in help, there is a link to example code on how to use it.

It is simple to use and it does work.  


With a memory mapped file you might need some sort of synchronisation mechanism between the apps (such as passing a message) so as to inform one app that the other has made a change.
0
 
rxzangAuthor Commented:
That's a perfect solution!!!!!! Thank you sooooooo much for your time! Really appreciate it.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.