How do I share data in my DLL with an application or with other DLLs?
Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of all the DLLs global and static variables. If your DLL needs to share data with other instances of it loaded by other applications, you can use either of the following approaches:
- Create named data sections using the data_seg pragma.
- Use memory mapped files. See the Win32 documentation on memory mapped files.
Here is an example of using the data_seg pragma:
#pragma data_seg (".myseg") int i = 0; char an = "hello world"; #pragma data_seg()
data_seg can be used to create a new named section (.myseg in this example). The most typical usage is to call the data segment .shared for clarity. You then must specify the correct sharing attributes for this new named data section in your .def file or with the linker option /SECTION:.MYSEC,RWS.
There are restrictions to consider before using a shared data segment:
- Any variables in a shared data segment must be statically initialized. In the above example, i is initialized to 0 and a is 32 characters initialized to hello world.
- All shared variables are placed in the compiled DLL in the specified data segment. Very large arrays can result in very large DLLs. This is true of all initialized global variables.
- Never store process-specific information in a shared data segment. Most Win32 data structures or values (such as HANDLEs) are really valid only within the context of a single process.
- Each process will get its own address space. It is very important that pointers are never stored in a variable contained in a shared data segment. A pointer may be perfectly valid in one application but not in another.
- It is possible that the DLL itself could get loaded at a different address in the virtual address spaces of each process. It is not safe to have pointers to functions in the DLL or to other shared variables.
Note that these last three points apply to memory-mapped files and shared data segments.
Memory-mapped files have an advantage over shared data sections because the start of the memory-mapped file is known. Developers can implement pointer-like behavior by using "offset from the start of the shared memory section" in all data located inside the shared memory. __based pointers are highly recommended for making this fast and easy. However, it is important to remember that the base (or start of the memory mapped file) could be different in each process, so the variable storing the base for __based pointers cannot itself be in the shared memory.
These restrictions have important implications to C++ classes.
- Classes with virtual functions always contain function pointers. Classes with virtual functions should never be stored in shared data segments nor in memory mapped files. This is particularly important to MFC classes or classes that inherit from MFC.
- Static data members are implemented as the equivalent of global variables. This means that each process would have its own copy of that class's static data members. Classes with static data members should not be shared.
- The initialization requirement of a shared data segment causes a particular problem for C++ classes. If you have something like
CTest Counter(0);in a shared data segment, the
Counterobject will get initialized in each process as they load the DLL, potentially zeroing out the object's data each time. This is very different than intrinsic data types that are initialized by the linker when it creates the DLL.
Because of these restrictions, Microsoft does not recommend sharing C++ objects between processes. In general, if you want to use C++ to share data between processes, write a class that internally uses a memory mapped file to share data, but do not share the class instances themselves. This may require special care in developing such a class, but it enables application developers to fully control the side effects of sharing data.
For more information about creating named data sections, see the following Knowledge Base articles at http://support.microsoft.com:
- How to Share Data Between Different Mappings of a DLL (Q125677).
- Specifying Shared and Nonshared Data in a DLL (Q100634).
- Sharing All Data in a DLL (Q109619).
- Memory in Shared Code Sections Is Not Shared Across Terminal Server Sessions (Q251045)