因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。
在DLL的实现文件中添加下列代码:
#pragma data_seg("DLLSharedSection") // 声明共享数据段,并命名该数据段
int SharedData = 123; // 必须在定义的同时进行初始化!!!!
#pragma data_seg()
在#pragma data_seg("DLLSharedSection")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有三种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加入如下语句:
SETCTIONS
DLLSharedSection READ WRITE SHARED
另一种方法是在项目设置的链接选项(Project Setting --〉Link)中加入如下语句:
/SECTION:DLLSharedSection,rws
还有一种就是使用指令:
#pragma comment(linker,"/section:.DLLSharedSection,rws")
那么这个数据节中的数据可以在所有DLL的实例之间共享了。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。
当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。
下面来谈一下在具体使用共享数据段时需要注意的一些问题:
· 所有在共享数据段中的变量,只有在数据段中经过了初始化之后,才会是进程间共享的。如果没有初始化,那么进程间访问该变量则是未定义的。
· 所有的共享变量都要放置在共享数据段中。如何定义很大的数组,那么也会导致很大的DLL。
· 不要在共享数据段中存放进程相关的信息。Win32中大多数的数据结构和值(比如HANDLE)只在特定的进程上下文中才是有效地。
· 每个进程都有它自己的地址空间。因此不要在共享数据段中共享指针,指针指向的地址在不同的地址空间中是不一样的。
· DLL在每个进程中是被映射在不同的虚拟地址空间中的,因此函数指针也是不安全的。
当然还有其它的方法来进行进程间的数据共享,比如文件内存映射等,这就涉及到通用的进程间通信了,这里就不多讲了。
下面是具体代码实现:
<span style="color:#FF0000;">//ShareDll.dll code</span>
#include "stdafx.h"
#include <stdio.h>
#pragma data_seg("ShareSec")
int globalint = 0;//把globalint放入ShareSec段
#pragma data_seg()
#pragma comment(linker,"/SECTION:ShareSec,RWS")//告诉编译器为ShareSec段添加共享段读写属性
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
printf("globalint = %d \n",globalint);
globalint = 5;
return TRUE;
}
<span style="color:#FF0000;">//LoadDll.exe code</span>
#include "stdafx.h"
#include <windows.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
HANDLE m_hDll;
m_hDll=LoadLibraryA(".\\ShareDLL");
getchar();
return 0;
}
用peid看看新创建的段:

已经创建成功了,再用测试代码看看结果吧: