Firstly, your DLL does not need to have any association with MFC. For a shared memory implementation it doesn't seem necessary to me at all.
Secondly, it is highly recommended that you do very, very little in your DLLmain code. Microsoft's docs state this also. That's because not all libraries have been fully initialized so you may encounter errors.
Lastly, as Richard mentioned, you don't need a DLL to do this but you certainly can use one. I use static libraries almost exclusively these days and they can accomplish all of the same things except they can't be explicitly loaded and that's OK with me because I don't need or want that.
Anyway, the best way to do this is to make an Initialize or MapMemory function, or what ever you want to call it, and let it map to the shared memory for you. All libraries will be full initialized by the time it is called so this should work OK. I do not recommend that you use callbacks. I find them to be too error-prone. I have better success with signalling events or posting messages. I recently implemented a highly modular system using what I refer to as a subscription model. It allows apps and/or threads to subscribe to events. What that means is a list is kept in shared memory where an app or thread can add the name of an event that gets signalled when certain things occur that they want to know about. This works really well for me.
An alternative that is a bit simpler is you can make a list in shared memory that an app, thread, or window; what ever; will add its window handle and a message code to. This should be protected by a mutex so they don't overwrite each other. When data is available the data source can post a message (
PostMessage
) to the specified handle with the message code listed. There are two additional arguments available in the message you can use for what ever you want. One idea is to have a array of data and when it is available put it in a slot and then tell the subscriber which slot it is in using the WPARAM or LPARAM of the message you send to it. The subscriber will receive the specified message when the data is available in its normal message loop. Threads can have message loops too so this scheme has a lot of flexibility.
Here's a subscription entry structure you can use that can live in shared memory.
struct SubscriptionEntry
{
HWND handle;
int msgId; int wparam; };
this one assumes the slot index of the data will be placed in the LPARAM of the message. There lots of ways you use this kind of thing. You could have a list for every kind of data you have with multiple subscribers in each one. When data is available you could send it too all the subscribers on the list. In my system, I have a shared memory directory of 255 subscription lists, each with up to 16 subscribers. It uses signalling events because the worker threads don't have message loops but that's just my implementation. It is otherwise very similar.
I hope this helps. If you need clarification feel free to ask.