The following example demonstrates how the DLL entry-point function can use a file-mapping object to set up memory that can be shared by processes that load the DLL. The shared DLL memory persists only as long as the DLL is loaded. Applications can use the SetSharedMem and GetSharedMem functions to access the shared memory.
DLL that Implements the Shared Memory
The example uses file mapping to map a block of named shared memory into the virtual address space of each process that loads the DLL. To do this, the entry-point function must:
- Call the CreateFileMapping function to get a handle to a file-mapping object. The first process that loads the DLL creates the file-mapping object. Subsequent processes open a handle to the existing object. For more information, see Creating a File-Mapping Object.
- Call the MapViewOfFile function to map a view into the virtual address space. This enables the process to access the shared memory. For more information, see Creating a File View.
Note that while you can specify default security attributes by passing in a NULL value for the lpAttributes parameter of CreateFileMapping, you may choose to use a SECURITY_ATTRIBUTES structure to provide additional security.
// The DLL code #include <windows.h> #include <memory.h> #define SHMEMSIZE 4096 static LPVOID lpvMem = NULL; // pointer to shared memory static HANDLE hMapObject = NULL; // handle to file mapping // The DLL entry-point function sets up shared memory using a // named file-mapping object. BOOL WINAPI DllMain(HINSTANCE hinstDLL, // DLL module handle DWORD fdwReason, // reason called LPVOID lpvReserved) // reserved { BOOL fInit, fIgnore; switch (fdwReason) { // DLL load due to process initialization or LoadLibrary case DLL_PROCESS_ATTACH: // Create a named file mapping object hMapObject = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits SHMEMSIZE, // size: low 32-bits TEXT("dllmemfilemap")); // name of map object if (hMapObject == NULL) return FALSE; // The first process to attach initializes memory fInit = (GetLastError() != ERROR_ALREADY_EXISTS); // Get a pointer to the file-mapped shared memory lpvMem = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_WRITE, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file if (lpvMem == NULL) return FALSE; // Initialize memory if this is the first process if (fInit) memset(lpvMem, '\0', SHMEMSIZE); break; // The attached process creates a new thread case DLL_THREAD_ATTACH: break; // The thread of the attached process terminates case DLL_THREAD_DETACH: break; // DLL unload due to process termination or FreeLibrary case DLL_PROCESS_DETACH: // Unmap shared memory from the process's address space fIgnore = UnmapViewOfFile(lpvMem); // Close the process's handle to the file-mapping object fIgnore = CloseHandle(hMapObject); break; default: break; } return TRUE; UNREFERENCED_PARAMETER(hinstDLL); UNREFERENCED_PARAMETER(lpvReserved); } // The export mechanism used here is the __declspec(export) // method supported by Microsoft Visual Studio, but any // other export method supported by your development // environment may be substituted. #ifdef __cplusplus // If used by C++ code, extern "C" { // we need to export the C interface #endif // SetSharedMem sets the contents of the shared memory __declspec(dllexport) VOID __cdecl SetSharedMem(LPWSTR lpszBuf) { LPWSTR lpszTmp; DWORD dwCount=1; // Get the address of the shared memory block lpszTmp = (LPWSTR) lpvMem; // Copy the null-terminated string into shared memory while (*lpszBuf && dwCount<SHMEMSIZE) { *lpszTmp++ = *lpszBuf++; dwCount++; } *lpszTmp = '\0'; } // GetSharedMem gets the contents of the shared memory __declspec(dllexport) VOID __cdecl GetSharedMem(LPWSTR lpszBuf, DWORD cchSize) { LPWSTR lpszTmp; // Get the address of the shared memory block lpszTmp = (LPWSTR) lpvMem; // Copy from shared memory into the caller's buffer while (*lpszTmp && --cchSize) *lpszBuf++ = *lpszTmp++; *lpszBuf = '\0'; } #ifdef __cplusplus } #endif
Shared memory can be mapped to a different address in each process. For this reason, each process has its own instance of lpvMem, which is declared as a global variable so that it is available to all DLL functions. The example assumes that the DLL global data is not shared, so each process that loads the DLL has its own instance of lpvMem.
Note that the shared memory is released when the last handle to the file-mapping object is closed. To create persistent shared memory, you would need to ensure that some process always has an open handle to the file-mapping object.
Processes that Use the Shared Memory
The following processes use the shared memory provided by the DLL defined above. The first process calls SetSharedMem to write a string while the second process calls GetSharedMem to retrieve this string.
This process uses the SetSharedMem function implemented by the DLL to write the string "This is a test string" to the shared memory. It also starts a child process that will read the string from the shared memory.
// Parent process #include <windows.h> #include <tchar.h> #include <stdio.h> extern "C" VOID __cdecl SetSharedMem(LPWSTR lpszBuf); HANDLE CreateChildProcess(LPTSTR szCmdline) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bFuncRetn = FALSE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); // Set up members of the STARTUPINFO structure. ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); // Create the child process. bFuncRetn = CreateProcess(NULL, szCmdline, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION if (bFuncRetn == 0) { printf("CreateProcess failed (%)\n", GetLastError()); return INVALID_HANDLE_VALUE; } else { CloseHandle(piProcInfo.hThread); return piProcInfo.hProcess; } } int _tmain(int argc, TCHAR *argv[]) { HANDLE hProcess; if (argc == 1) { printf("Please specify an input file"); ExitProcess(0); } // Call the DLL function printf("\nProcess is writing to shared memory...\n\n"); SetSharedMem(L"This is a test string"); // Start the child process that will read the memory hProcess = CreateChildProcess(argv[1]); // Ensure this process is around until the child process terminates if (INVALID_HANDLE_VALUE != hProcess) { WaitForSingleObject(hProcess, INFINITE); CloseHandle(hProcess); } return 0; }
This process uses the GetSharedMem function implemented by the DLL to read a string from the shared memory. It is started by the parent process above.
// Child process #include <windows.h> #include <tchar.h> #include <stdio.h> extern "C" VOID __cdecl GetSharedMem(LPWSTR lpszBuf, DWORD cchSize); int _tmain( void ) { WCHAR cBuf[MAX_PATH]; GetSharedMem(cBuf, MAX_PATH); printf("Child process read from shared memory: %S\n", cBuf); return 0; }
沒有留言:
張貼留言