Solved

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

Posted on 2009-04-09
20
1,223 Views
Last Modified: 2013-12-14
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
0
Comment
Question by:rxzang
  • 9
  • 8
  • 2
  • +1
20 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 24112578
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 24113709
Look at WM_COPYDATA in help, there is a link to example code on how to use it.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24136234
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24136281
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
 

Author Comment

by:rxzang
ID: 24141511
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24142738
>>>> 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
 

Author Comment

by:rxzang
ID: 24143043
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24143250
Try

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


Should be
 
UnmapViewOfFile(myPtrMem);
0
 

Author Comment

by:rxzang
ID: 24143392
new error:
'CreateFileMappingW' : function does not take 7 arguments

UnmapViewOfFile seems to work.

Thanks!!!
0
 

Author Comment

by:rxzang
ID: 24143828
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:rxzang
ID: 24152880
Do you know why sm.isvalid() is false?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24153845
>>>> '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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24153855
>>>> 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
 

Author Comment

by:rxzang
ID: 24161691
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24163606
>>>> 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
 

Author Comment

by:rxzang
ID: 24163824
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24164092
>>>> 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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 24165238
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
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 500 total points
ID: 24181132
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
 

Author Closing Comment

by:rxzang
ID: 31568784
That's a perfect solution!!!!!! Thank you sooooooo much for your time! Really appreciate it.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now