本节介绍了DLL入口点函数如何使用文件映射对象来设置可由加载DLL的进程共享的内存。只要DLL被加载,共享的DLL内存就会持续存在。
该示例使用文件映射将一个命名共享内存块映射到加载该DLL的每个进程的虚拟地址空间中。为此,入门点功能必须:
1.选择CreateFileMapping函数获取文件映射对象的句柄。加载DLL的第一个进程创建文件映射对象。后续进程打开现有对象的句柄。有关详细信息,请参阅创建文件映射对象.
2.选择MapViewOfFile功能将视图映射到虚拟地址空间。这使得进程能够访问共享内存。有关详细信息,请参阅创建文件视图.
//文件:DLLSHMEM.C。
// DLL入口点函数使用共享内存设置
//一个命名的文件映射对象。
#include < windows.h >
#include < memory.h >
// pointer to shared memory
static LPVOID lpvMem = NULL; //指向共享内存的指针
BOOL DllEntryPoint(HINSTANCE hinstDLL, // DLL模块句柄
DWORD fdwReason, //原因叫
LPVOID lpvReserved) //保留
{
HANDLE hMapObject = NULL; //处理文件映射
BOOL fInit, fIgnore;
开关(fdwReason)
{
//由于进程,DLL正在加载
//初始化或调用LoadLibrary。
case DLL_PROCESS_ATTACH:
//创建一个命名文件映射对象。
hMapObject = CreateFileMapping(
(HANDLE) 0xFFFFFFFF, //使用页面文件
NULL, //没有安全属性
PAGE_READWRITE, //读/写访问
0, // size:high 32-bit
SHMEMSIZE, // size:low 32-bit
"dllmemfilemap"); //地图对象的名称
if (hMapObject == NULL)
return FALSE;
//附加的第一个进程初始化内存。
fInit = (GetLastError() != ERROR_ALREADY_EXISTS);
//获取指向文件映射的共享内存的指针。
lpvMem = MapViewOfFile(
hMapObject, //对象映射视图
FILE_MAP_WRITE, //读/写访问
0, // high offset:map from
0, //低偏移量:开始
0); // default:映射整个文件
if (lpvMem == NULL)
return FALSE;
//如果这是第一个进程,则初始化内存。
如果(端部)
memset(lpvMem, '\0', SHMEMSIZE);
break;
//附加的进程创建一个新的线程。
case DLL_THREAD_ATTACH:
break;
//附加进程的线程终止。
case DLL_THREAD_DETACH:
break;
//由于DLL正在从进程卸载
//进程终止或调用FreeLibrary。
case DLL_PROCESS_DETACH:
//从进程的地址空间取消映射共享内存。
fIgnore = UnmapViewOfFile(lpvMem);
//关闭进程对文件映射对象的句柄。
fIgnore = CloseHandle(hMapObject);
break;
默认:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}
SetSharedMem //将共享存储器的内容。
VOID SetSharedMem(LPTSTR lpszBuf)
{
LPTSTR lpszTmp;
//获取共享内存块的地址。
lpszTmp = (LPTSTR) lpvMem;
//将空值终止的字符串复制到共享内存中。
而(* lpszBuf)
*lpszTmp++ = *lpszBuf++;
*lpszTmp = '\0';
}
// GetSharedMem获取共享内存的内容。
VOID GetSharedMem(LPTSTR lpszBuf,DWORD cchSize)
{
LPTSTR lpszTmp;
//获取共享内存块的地址。
lpszTmp = (LPTSTR) lpvMem;
//从共享内存复制到调用者的缓冲区。
while(* lpszTmp & & --cchSize)
*lpszBuf++ = *lpszTmp++;
*lpszBuf = '\0';
}
请注意,共享内存可以映射到每个进程中的不同地址。因此,每个进程都有自己的【Note that the shared memory can be mapped to a different address in each process.】参数实例,它被声明为一个全局变量,以便它可用于所有的DLL函数。该示例假定DLL全局数据不共享,因此加载DLL的每个进程都有自己的【Note that the shared memory can be mapped to a different address in each process.】实例。
在此示例中,当文件映射对象的最后一个句柄关闭时,共享内存将被释放。要创建持久共享内存,DLL可以在首次加载DLL时创建一个分离的进程(参见CreateProcess)。如果这个分离的进程使用该DLL并且不会终止,那么它具有一个文件映射对象的句柄,可以防止共享内存被释放。