Verwenden des freigegebenen Arbeitsspeichers in einer Dynamic-Link-Bibliothek
Im folgenden Beispiel wird veranschaulicht, wie die DLL-Einstiegspunktfunktion ein Dateizuordnungsobjekt verwenden kann, um Arbeitsspeicher einzurichten, der von Prozessen freigegeben werden kann, die die DLL laden. Der freigegebene DLL-Arbeitsspeicher bleibt nur so lange erhalten, wie die DLL geladen wird. Anwendungen können die Funktionen SetSharedMem und GetSharedMem verwenden, um auf den freigegebenen Arbeitsspeicher zuzugreifen.
DLL, die den freigegebenen Arbeitsspeicher implementiert
Im Beispiel wird die Dateizuordnung verwendet, um einen Block mit benanntem freigegebenem Arbeitsspeicher dem virtuellen Adressraum jedes Prozesses zuzuordnen, der die DLL lädt. Dazu muss die Einstiegsfunktion Folgendes tun:
- Rufen Sie die CreateFileMapping-Funktion auf, um ein Handle für ein Dateizuordnungsobjekt abzurufen. Der erste Prozess, der die DLL lädt, erstellt das Dateizuordnungsobjekt. Nachfolgende Prozesse öffnen ein Handle für das vorhandene Objekt. Weitere Informationen finden Sie unter Erstellen eines File-Mapping-Objekts.
- Rufen Sie die MapViewOfFile-Funktion auf, um dem virtuellen Adressraum eine Ansicht zuzuordnen. Dadurch kann der Prozess auf den freigegebenen Arbeitsspeicher zugreifen. Weitere Informationen finden Sie unter Erstellen einer Dateiansicht.
Beachten Sie, dass Sie zwar Standardsicherheitsattribute angeben können, indem Sie einen NULL-Wert für den lpAttributes-Parameter von CreateFileMapping übergeben, sie jedoch eine SECURITY_ATTRIBUTES-Struktur verwenden können, um zusätzliche Sicherheit zu bieten.
// 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
Freigegebener Arbeitsspeicher kann in jedem Prozess einer anderen Adresse zugeordnet werden. Aus diesem Grund verfügt jeder Prozess über eine eigene instance von lpvMem, das als globale Variable deklariert wird, sodass er für alle DLL-Funktionen verfügbar ist. Im Beispiel wird davon ausgegangen, dass die globalen DLL-Daten nicht freigegeben werden, sodass jeder Prozess, der die DLL lädt, über eine eigene instance von lpvMem verfügt.
Beachten Sie, dass der freigegebene Arbeitsspeicher freigegeben wird, wenn das letzte Handle für das Dateizuordnungsobjekt geschlossen wird. Um persistenten freigegebenen Arbeitsspeicher zu erstellen, müssen Sie sicherstellen, dass ein Prozess immer über ein geöffnetes Handle für das Dateizuordnungsobjekt verfügt.
Prozesse, die den freigegebenen Arbeitsspeicher verwenden
Die folgenden Prozesse verwenden den freigegebenen Arbeitsspeicher, der von der oben definierten DLL bereitgestellt wird. Der erste Prozess ruft SetSharedMem auf, um eine Zeichenfolge zu schreiben, während der zweite Prozess GetSharedMem aufruft, um diese Zeichenfolge abzurufen.
Dieser Prozess verwendet die setSharedMem-Funktion, die von der DLL implementiert wird, um die Zeichenfolge "Dies ist eine Testzeichenfolge" in den freigegebenen Arbeitsspeicher zu schreiben. Außerdem wird ein untergeordneter Prozess gestartet, der die Zeichenfolge aus dem freigegebenen Arbeitsspeicher liest.
// 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;
}
Dieser Prozess verwendet die von der DLL implementierte GetSharedMem-Funktion, um eine Zeichenfolge aus dem freigegebenen Arbeitsspeicher zu lesen. Es wird vom übergeordneten Prozess oben gestartet.
// 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;
}
Zugehörige Themen