Menggunakan Memori Bersama di Pustaka Dynamic-Link
Contoh berikut menunjukkan bagaimana fungsi titik entri DLL dapat menggunakan objek pemetaan file untuk menyiapkan memori yang dapat dibagikan oleh proses yang memuat DLL. Memori DLL bersama hanya bertahan selama DLL dimuat. Aplikasi dapat menggunakan fungsi SetSharedMem dan GetSharedMem untuk mengakses memori bersama.
DLL yang Mengimplementasikan Memori Bersama
Contohnya menggunakan pemetaan file untuk memetakan blok memori bersama bernama ke ruang alamat virtual dari setiap proses yang memuat DLL. Untuk melakukan ini, fungsi titik entri harus:
- Panggil fungsi CreateFileMapping untuk mendapatkan handel ke objek pemetaan file. Proses pertama yang memuat DLL membuat objek pemetaan file. Proses berikutnya membuka handel ke objek yang ada. Untuk informasi selengkapnya, lihat Membuat Objek File-Mapping.
- Panggil fungsi MapViewOfFile untuk memetakan tampilan ke ruang alamat virtual. Ini memungkinkan proses untuk mengakses memori bersama. Untuk informasi selengkapnya, lihat Membuat Tampilan File.
Perhatikan bahwa meskipun Anda dapat menentukan atribut keamanan default dengan meneruskan nilai NULL untuk parameter lpAttributes dari CreateFileMapping, Anda dapat memilih untuk menggunakan struktur SECURITY_ATTRIBUTES untuk memberikan keamanan tambahan.
// 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
Memori bersama dapat dipetakan ke alamat yang berbeda di setiap proses. Untuk alasan ini, setiap proses memiliki instans lpvMem sendiri, yang dinyatakan sebagai variabel global sehingga tersedia untuk semua fungsi DLL. Contoh mengasumsikan bahwa data global DLL tidak dibagikan, sehingga setiap proses yang memuat DLL memiliki instans lpvMem sendiri.
Perhatikan bahwa memori bersama dirilis ketika handel terakhir ke objek pemetaan file ditutup. Untuk membuat memori bersama persisten, Anda harus memastikan bahwa beberapa proses selalu memiliki handel terbuka ke objek pemetaan file.
Proses yang Menggunakan Memori Bersama
Proses berikut menggunakan memori bersama yang disediakan oleh DLL yang ditentukan di atas. Proses pertama memanggil SetSharedMem untuk menulis string sementara proses kedua memanggil GetSharedMem untuk mengambil string ini.
Proses ini menggunakan fungsi SetSharedMem yang diimplementasikan oleh DLL untuk menulis string "Ini adalah string pengujian" ke memori bersama. Ini juga memulai proses anak yang akan membaca string dari memori bersama.
// 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;
}
Proses ini menggunakan fungsi GetSharedMem yang diimplementasikan oleh DLL untuk membaca string dari memori bersama. Ini dimulai oleh proses induk di atas.
// 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;
}
Topik terkait
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk