windows共享内存

共享内存在   Windows   中是用   FileMapping   实现的。我们可以用   CreateFileMapping   创建一个内存文件映射对象,   CreateFileMapping   这个   API   将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的文件,所以,就不需要调用   CreateFile   创建一个文件,   hFile   这个参数可以填写   INVALID_HANDLE_VALUE   。但是,文件长度是需要填的。Windows   支持长达   64bit   的文件,但是这里,我们的需求一定不会超过   4G   ,   dwMaximumSizeHigh   一定是   0   ,长度填在   dwMaximumSizeLow   即可。然后调用   MapViewOfFile   映射到当前进程的虚拟地址上即可。一旦用完共享内存,再调用   UnmapViewOfFile   回收内存地址空间。  
   
  Windows   把   CreateFileMapping   和   MapViewOfFile   两个   API   分开做是有它的道理的。这是因为允许映射一个超过   4G   的文件,而地址空间最大只有   4G   (实际上,一般用户的程序只能用到   2G)   ,   MapViewOfFile   就可以指定文件的   Offset   而只映射一部分。  
   
  在   CreateFileMapping   的最后一个参数   pszName   填写一个名字,那么别的进程就可以用这个名字去调用   OpenFileMapping   来打开这个   FileMapping   对象,在新的进程内作映射。   不过,通过约定字符串的方法似乎不太优雅。  
   
  一个优雅的方法是,用   DuplicateHandle   在新进程中复制一份   FileMapping   对象出来,然后想办法把   Handle   通知新进程,比如用消息的方式传递过去。  
   
  如果需要共享内存的两个进程是父子关系,那么我们可以不用消息传递的方式来通知   FileMapping   的   Handle   。父进程可以用继承   Handle   的方式直接把   FileMapping   的   Handle   传递到子进程中。当然,在   CreateFileMapping   时就应该设置可以被继承的属性。  
   
  大约是这样:  
   
  SECURITY_ATTRIBUTES   sa;  
  sa.nLength=sizeof(sa);  
  sa.lpSecurityDescriptor=NULL;  
  sa.bInheritHandle=TRUE;  
  handle=CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_READWRITE,0,size,NULL);  
   
  这样,在   CreateProcess   的时候,如果   bInheritHandles   参数为   TRUE   ,所有有可被继承属性的内核对象都会被复制到子进程中。  
   
  注:内核对象的继承就是在   CreateProcess   创建子进程,但是子进程的主线程尚未活动之前,内核扫描当前进程中所有内核对象,检查出有可继承属性的那些,再用   DuplicateHandle   复制一份到子进程。由于是内核对象,在内核中实质只有一份,所有只是引用记数加一,父进程和子进程对同一内核对象的   Handle   一定是相同的。  
   
  复制内核对象的过程是由   CreateProcess   内部完成的,我们可以放心的把对象   Handle   (和子进程相同)   通过命令行传递给子进程。或者,用环境变量传递也可以。  
   
  值得注意的是,子进程用完了这个   FileMapping   对象后一样需要   CloseHandle   减去引用计数。  
   
  备注:  
  CreateProcess   调用时,pszCommandLine   不能直接填上一个不可修改的字符串。例如:  
   
  CreateProcess("test.exe","test   argument",...);  
   
  这样就是错误的,因为   "test   argument"   会被编译器编译放到不可修改的数据段中。正确的方法是:  
   
  char   cmdline[]="test   argument";  
  CreateProcess("test.exe",cmdline,...);  
   
  这样,命令行的字符串就被放在堆栈上,是可以被读写的。  
   
  CreateProcess   的倒数第二个参数需要填写一个   STARTUPINFOW   结构,这个结构很复杂,通常填起来很麻烦。我们可以复制一份父进程的结构,再酌情修改。方法是:  
   
  STARTUPINFO   si={sizeof(si)};  
  PROCESS_INFORMATION   pi;  
  GetStartupInfo(&si);  
  CreateProcess(...,&si,&   pi);   
      这里,   STARTUPINFO   结构的第一个长度信息通常应该填上,保证   GetStartupInfo(&si);   的正确执行。 

下面是另一个人写的

通过windows api我们可以很容易的在内存中创建这么一个区域并轻易的读取它。这里需要用到两个关键的api函数:CreateFileMapping和MapViewOfFile,前者在内存中创建一个内存映象区,它需要一些参数包括这块区域的读写权限,唯一区域名称以及数据大小(这些参数将在下面代码的注释中给予说明,更多的参数说明请参看win sdk的帮助文件或查看msdn);后者返回一个指向这块区域的指针以便在程序中调用。下面我们将通过一个简单的例子来说明,这个例子由两个工程组成,一个通过一个按纽负责向内存映象区写入一个长度为11个字符的字符串(‘how are you‘,通过一个edit读入,如果edit中的字符数大于了11个程序将可能出错),另一个则通过一个按纽读出这个字符串,写入一个edit中。下面是部分的代码(为了节省篇幅,加上程序很简单,有些不会影想你阅读的代码没有贴出):

我们首先在第一个工程(窗口取名为SetValue)的单元的接口部分声明一个指向即将创建的内存区域的句柄和一个用来向这个区域写数据的指针变量:

var

  ……

  hFileMapping:HWND;//指向内存区域的句柄

  SetString:pchar;//这里应该使用标准的windows字符串而非delphi特有的string类型

这样我们可以在按纽的单击事件中编写相应的代码:

procedure TForm1.Button1Click(Sender: TObject);

begin

 hFileMapping:=CreateFileMapping($FFFFFFFF,nil,Page_ReadWrite,0,11,'MapString');

 //$FFFFFFFF表示使用虚拟文件,注意两个工程中应该使用同一个唯一的名称MapString

 if hFileMapping=0 then

  raise Exception.Create('Error creating map file!');

 SetString:=MapViewOfFile(hFileMapping,File_Map_Write,0,0,11);

 strcopy(SetString,pchar(Edit1.Text));

 //注意这里应该使用拷贝函数而不是直接赋值 SetString:=pchar(Edit1.Text)

end;

当然,我们还可以在这个主工程中编写一个释放内存映象的过程:

procedure TForm1.Button2Click(Sender: TObject);

begin

 UnMapViewOfFile(SetString);

 if hFileMapping<>0 then

  closehandle(hFileMapping);

end;

接下来是第2个工程的按纽单击事件,它和第一个工程几乎没有什么不同,只是我们修改了内存映象的读取权限为只读而以:

var

  ……

  GetString:pchar;

  hMapFileMaping:HWND;

procedure TForm1.Button1Click(Sender: TObject);

begin

 hMapFileMaping:=CreateFileMapping($FFFFFFFF,nil,Page_ReadOnly,0,11,'MapString');

//再次注意一定要使用唯一的名称(MapString)和第一个工程保持一致

 if hMapFileMaping=0 then

  raise Exception.Create('Error');

 GetString:=MapViewOfFile(hMapFileMaping,File_Map_Read,0,0,11);

 Edit1.Text:=String(GetString);

end; 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值