Question

I have a server library which my client executable injects into a remote process. It is the server's responsibility to set up some sort of IPC/RPC implementation to allow the client to seamlessly communicate with the remote process.

Update

Take a look at the following server-side header:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
using namespace boost::interprocess;

typedef allocator<int, managed_shared_memory::segment_manager> ShmIntAllocator;
typedef vector<int, ShmIntAllocator> IntVector;

class A
{
public:
    A();
    A(string str, offset_ptr<IntVector> ints)
        : m_str(string(str)), m_ints(ints) {};
    ~A();

    string m_str;
    offset_ptr<IntVector> m_ints;
};

class B
{
public:
    B();
    B(offset_ptr<A> obj) : m_obj(obj);
    ~B();
    VOID DoSomethingUseful()
    {
        MessageBoxA(NULL, m_obj->m_str.c_str(), "SomethingUseful", MB_ICONINFORMATION);
    }

    offset_ptr<A> m_obj;
};

And here's the server-side implementation:

managed_shared_memory g_shm;
offset_ptr<A> g_objA = nullptr;
PVOID g_hMem = nullptr;

BOOL StartServer()
    // Create a shared memory pool
    try {
        g_shm = managed_shared_memory(create_only, "MySharedMem", OVR_MAPSIZE);
    } catch(interprocess_exception& e) {
        std::string msg(e.what());
        MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
        return FALSE;
    }

    // Construct a local class instance
    const ShmIntAllocator alloc_intVector (g_shm.get_segment_manager());
    offset_ptr<IntVector> ints = g_shm.construct<IntVector>(unique_instance)(alloc_intVector);
    ints->push_back(10);
    ints->push_back(20);
    ints->push_back(30);
    g_objA = new A("Testing", ints);
    B objB(g_objA);

    // Copy data into shared memory
    size_t len = sizeof(objB); // <-- Doesn't seem to make a difference if I set this to be something higher
    g_hMem = g_shm.allocate(len);
    std::memcpy(g_hMem, &objB, len);
    return TRUE;
}

VOID StopServer()
{
    // Free used resources

    if(g_objA) {
        delete g_objA;
        g_objA = nullptr;
    }

    try{
        g_shm.destroy<B>(unique_instance);
        g_shm.deallocate(g_hMem);
        g_hMem = nullptr;
        shared_memory_object::remove("MySharedMem");
    } catch(interprocess_exception& e) {
        std::string msg(e.what());
        MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
    }
}

And the client implementation:

BOOL Connect()
{
    // Grab the shared memory pool and extract the class
    managed_shared_memory shm(open_only, "MySharedMem");
    std::pair<B*, std::size_t> ret = shm.find<B>(unique_instance); // <-- Always ends up being 0x00000000!
    B *objB = static_cast<B*>(ret.first);
    if(!objB) return FALSE;
    objB->DoSomethingUseful();
    return TRUE;
}


You'll notice that managed_shared_memory::find() always fails to return a valid pointer to the client. But as far as I can tell, the code is perfectly valid. There are no compiler warnings or errors, and everything appears to run smoothly up until this point.

So why is this failing? How can I get this to work as expected?

Was it helpful?

Solution 2

You are trying to find B that supposed be created by Unique instance construction. Boost documentation says

The find function obtains a pointer to the only object of type T that can be created using this "unique instance" mechanism.

but in your code you are allocating raw memory and just copy your B object. So your B was not created as Unique instance

So i would suggest change your code as following: try use

B &objB = *g_shm.construct<B>(unique_instance) (g_objA);

instead of

B objB(g_objA);

OTHER TIPS

Distinct address spaces for pointers

When you are sharing values, everything is clear. For example when put a float value such as 1234.5 in the shared memory, in the other side you can read it simply.

But when you are sharing complex objects (which contain pointers) there is an important problem. The address space of two processes are completely different and distinct. For example you can not put a std::vector object in the shared memory, because it has a pointer to its data in process1 e.g. 0x1ABF212 and this number is meaningless for process2.

So, you have to write down the items of std::vector one by one in the shared memory. Read about Serialization technique to share complex data.

Also, if you're insisting to share complex object as a unique object between processes, you can make those objects with specific memory allocators.

AFAIK Boost.Interprocess has that allocators. It manages shared memory and makes pointers inside the shared memory which is meaningful for both processes.

Sorry for ambiguity, My bad English

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top