Delphi自学系列_4_Delphi下的内核映像文件引用机制
很久没有总结一下最近的学习了, 因为公司的事情实在是太忙了,忙的晕头转向,
每天下班后什么也不想做,就想躺在床上睡一觉。
今天说些什么呢?估计了解Linux的人都会听说过内核这个名词,这个名词在linux的世界里
接触的机会应该比win下的多,在win下一般需要有一定的积累后才会接触到这个名词,而我曾经
听到过一个很雷的说法:win没有内核。我也不知道为什么会有人有这样的认识;可能是Win的面向
对象比Linux来的彻底,才会使人有这样的认识(说笑而已,哈哈,实际上win大部分是C实现的,小
部分是用C++实现的,而只有非常微小的部分是用汇编实现的)。
这应该是win封装的太厉害的缘故吧。
Win下编程的人一般会听说过内核对象这个名词,那本书上说过,书名我就不说了,现在有中文的,
当然也有原文的,那我们今天来说说win下的内核映像文件。
一:引子
在Win32中,通过使用内核映像文件可以在进程间实现共享文件或共享内存数据块的功能。如果在
一个进程或Exe文件中建立一个Win全局的映像名字或文件句柄,则其他的进程或者Exe文件可以通过这个
唯一的Win全局映像名字或者文件句柄来引用这个内存映像文件。不同的进程通过引用一个指针来读写同一个
文件或者内存数据块来实现,并且可以把它映射到该进程或Exe文件的地址空间。
在9x、NT、2000向内存中装载文件时,使用了特殊的全局内存区。在这个全局内存区域内,应用程序的
虚拟地址空间和文件中的相应位置对应。由于所有的进程共享一个用于存储映像文件的全局内存区域,因而当
两个进程装载相同的模块时,实际访问的是内存中同一段代码区域。
内存映射文件可以映射一个文件、一个文件中的指定区域或者指定的内存块,这些数据可以用内存读写直接
访问。
内存映像文件可以用来支持永久命名的共享内存,要在两个应用程序中共享内存,可以在一个应用程序中创建
一个文件并映射这个映像文件;然后在另一个应用程序中可以通过打开和映射该文件,并把它作为自己进程中的内存
来使用。
二:使用映像文件的步骤
1、 创建内存映像文件
CreateMappingFile 函数来实现
2、打开内存映像文件
OpenFileMapping 函数来实现
3、映射到本进程中
MapViewOfFile 函数来实现
4、关闭内存映像文件
UnmapViewOfFile 函数来实现
通过这样一组win32 API来支持内存映像文件的使用,在win32上所有的共享内存依赖于win32内存映像文件I/O
的支持,一个内存映像文件使用共享内存来提供公共的基于文件的共享数据。
三: 内存映像文件的内核对象
内存映像文件的需要三个win内核对象支持: 文件、文件映像、视图
1、映像一个文件到内存的过程
打开文件——》 建立内存映像文件——》连接到内存。
2、为了在不同的进程间同步数据,win的内核映像机制提供了一个基于磁盘文件的逻辑连接
最终对数据块的访问通过映射的内存地址实现。
3、一个内存映像文件对象可以创建多个视图,可以分别存取文件不同的部分
四: 建立文件内存映像文件I/O的过程:
1、打开文件
CreateFile 函数 或 OpenFile 函数 实现
2、通过返回的文件句柄建立文件内存映像文件
CreateMappingFile 函数实现
3、创建视图对象,将文件映射到内存
MapViewOfFile 函数实现
下面我们通过一段D版的程序来看看如何在两个Exe文件中实现进程信息交换:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const WM_DATA=WM_USER+1024; //定义自定义消息 type PShareMem=^TShareMem; TShareMem=record Data:array[0..255]of char; end; TMyForm = class(TForm) Memo1: TMemo; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure GetShareInfo(var msg:TMessage);message WM_DATA; end; var MyForm: TMyForm; PShare:PShareMem; MapHandle:THandle; implementation {$R *.dfm} procedure TMyform.GetShareInfo(var msg:TMessage); begin if msg.LParam=1 THEN memo1.Text:=pshare^.Data; end; procedure TMyForm.FormCreate(Sender: TObject); begin MapHandle:=OpenFileMapping(FILE_MAP_WRITE, FALSE, pchar('Mapname') ); if MapHandle=0 then begin showmessage('不能定位内存映像文件'); halt; end; PShare:=PShareMem(MapViewOfFile(MapHandle,FILE_MAP_ALL_ACCESS,0,0,0)); IF PSHARE=NIL THEN BEGIN CloseHandle(MapHandle); Showmessage('不能打开内存映像文件'); application.Terminate; exit; end; FillChar(pshare^,sizeof(Tsharemem),0); end; procedure TMyForm.Button1Click(Sender: TObject); begin CloseHandle(MapHandle); close; end; end.
前面为接收消息的工程里的单元文件,下面为发送消息的工程单元文件
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const WM_DATA=WM_USER+1024; //自定义消息 type PShareMem=^TShareMem; TShareMem=record Data:array[0..255] of char; //共享数据 end; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; PShare:PShareMem; implementation {$R *.dfm} var HMapping:THandle; HMapMutex:THandle; const MAPFILESIZE=1000; REQUEST_TIMEOUT=1000; procedure OpenMap; begin //创建内存映像文件 HMapping:=CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TShareMem), pchar('Mapname') ); if HMapping=0 then begin showmessage('can not create memory mapping file'); application.Terminate; exit; end; //将内存映像文件映射到进程的地址空间 PShare:=PShareMem(MapViewOfFile(HMapping,FILE_MAP_ALL_ACCESS,0,0,0)); if PShare=nil then begin CloseHandle(HMapping); showmessage('can not view memory map'); application.Terminate; exit; end; end; procedure CloseMap; begin //从进程的地址空间中撤销映像文件 if PShare<> nil then UnMapViewOfFile(PShare); //关闭映像文件 if HMapping<>0 then CloseHandle(HMapping); end; function LockMap:boolean; //建立互斥对象 begin result:=true; HMapMutex:=CreateMutex(nil, false, pchar('My Mutex name goes here') ); if hmapmutex=0 then begin showmessage('can not create mutex object'); result:=false; end else begin if WaitForSingleObject(HMapmutex,REQUEST_TIMEOUT)=WAIT_FAILED then begin showmessage('can not create mutex object and lock'); result:=false; end; end; end; procedure UnlockMap; begin ReleaseMutex(HMapMutex); CloseHandle(HMapMutex); end; procedure TForm1.Button1Click(Sender: TObject); var str:pchar; begin str:=pchar('Exp of share memory mapping file'); CopyMemory(@(PShare^.data),str,Length(str)); PostMessage(FindWindow(nil,'MyForm'),WM_DATA,1,1); end; procedure TForm1.FormDestroy(Sender: TObject); begin UnLockMap; CloseMap; end; procedure TForm1.FormCreate(Sender: TObject); begin OpenMap; LockMap; end; end.
测试的时候需要现启动第二段代码编译产生的Exe文件。
哎,有点累了,而且有点晚了,本来打算再弄个C版的实例代码, 但是明天要上班,就等到周末吧,
好了不废话了,还是睡觉吧................