Solved

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

Posted on 2009-04-09
20
1,217 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>>>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
new error:
'CreateFileMappingW' : function does not take 7 arguments

UnmapViewOfFile seems to work.

Thanks!!!
0
 

Author Comment

by:rxzang
Comment Utility
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 

Author Comment

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

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> '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
Comment Utility
>>>> 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
Comment Utility
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
Comment Utility
>>>> 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
Comment Utility
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
Comment Utility
>>>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
That's a perfect solution!!!!!! Thank you sooooooo much for your time! Really appreciate it.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.

744 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

16 Experts available now in Live!

Get 1:1 Help Now