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.
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?
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);