在动态链接库中使用共享内存

【勇芳软件工作室】汉化HomePreviousNext

本节介绍了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并且不会终止,那么它具有一个文件映射对象的句柄,可以防止共享内存被释放。