Usando memória compartilhada em uma biblioteca de Dynamic-Link
O exemplo a seguir demonstra como a função de ponto de entrada DLL pode usar um objeto de mapeamento de arquivo para configurar a memória que pode ser compartilhada por processos que carregam a DLL. A memória DLL compartilhada persiste apenas desde que a DLL seja carregada. Os aplicativos podem usar as funções SetSharedMem e GetSharedMem para acessar a memória compartilhada.
DLL que implementa a memória compartilhada
O exemplo usa o mapeamento de arquivo para mapear um bloco de memória compartilhada nomeada para o espaço de endereço virtual de cada processo que carrega a DLL. Para fazer isso, a função de ponto de entrada deve:
- Chame a função CreateFileMapping para obter um identificador para um objeto de mapeamento de arquivo. O primeiro processo que carrega a DLL cria o objeto de mapeamento de arquivo. Os processos subsequentes abrem um identificador para o objeto existente. Para obter mais informações, consulte Criando um objeto File-Mapping.
- Chame a função MapViewOfFile para mapear uma exibição para o espaço de endereço virtual. Isso permite que o processo acesse a memória compartilhada. Para obter mais informações, consulte Criando um modo de exibição de arquivo.
Observe que, embora você possa especificar atributos de segurança padrão passando um valor NULL para o parâmetro lpAttributes de CreateFileMapping, você pode optar por usar uma estrutura SECURITY_ATTRIBUTES para fornecer segurança adicional.
// 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
A memória compartilhada pode ser mapeada para um endereço diferente em cada processo. Por esse motivo, cada processo tem sua própria instância de lpvMem, que é declarada como uma variável global para que ela esteja disponível para todas as funções DLL. O exemplo pressupõe que os dados globais da DLL não sejam compartilhados, portanto, cada processo que carrega a DLL tem sua própria instância de lpvMem.
Observe que a memória compartilhada é liberada quando o último identificador para o objeto de mapeamento de arquivo é fechado. Para criar memória compartilhada persistente, você precisaria garantir que algum processo sempre tenha um identificador aberto para o objeto de mapeamento de arquivo.
Processos que usam a memória compartilhada
Os processos a seguir usam a memória compartilhada fornecida pela DLL definida acima. O primeiro processo chama SetSharedMem para gravar uma cadeia de caracteres enquanto o segundo processo chama GetSharedMem para recuperar essa cadeia de caracteres.
Esse processo usa a função SetSharedMem implementada pela DLL para gravar a cadeia de caracteres "Esta é uma cadeia de caracteres de teste" na memória compartilhada. Ele também inicia um processo filho que lerá a cadeia de caracteres da memória compartilhada.
// 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;
}
Esse processo usa a função GetSharedMem implementada pela DLL para ler uma cadeia de caracteres da memória compartilhada. Ele é iniciado pelo processo pai acima.
// 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;
}
Tópicos relacionados