在win32中,通过使用映像文件在进程间实现共享文件或共享内存数据块,如果利用相同的映像名字或文件句柄,则不同的进程可以通过一个指针来读写一个文件或同一个内存数据块,并把它当做该进程内地址空间的一部分
在Windows9x/NT/200 向内存中装载文件时,使用了特殊的全局内存区。在该区域内,应用程序的虚拟内存地址和文件中的响应位置对应,由于所有进程恭喜了一个用于存储映像文件的全局内存区域,因而当两个进程装载相同模块(应用程序exe或dll文件)时,他们实际上是在内存中共享其执行代码
内存映像文件可以映射一个文件、一个文件中的指定区域或者指定的内存块,其中的数据就可以用内存读写指令直接访问,而不比频繁的调用ReadFile或WriteFIle这样的I/O系统函数,从而提高了文件存取速度和效率
发送数据端
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; const WM_DATA = WM_USER + 1024; type PShareMem = ^TPShareMem; TPShareMem = record //共享数据 Data: array[0..255] of Char; end; TForm1 = class(TForm) btn1: TButton; procedure btn1Click(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 MAP_FILE_SIZE = 1000; REQUEST_TIME_OUT = 1000; {打开建立共享内存} procedure OpenMap; begin {创建一个映像文件} HMapping := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TPShareMem), PChar('MapName')); if HMapping = 0 then begin ShowMessage('不能创建内存映像文件'); Exit end; {将映像文件映射到进程的地址空间} PShare := PShareMem(MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0)); if PShare = nil then begin CloseHandle(HMapping); ShowMessage('映像文件在内存中不存在'); Application.Terminate; Exit end; end; {关闭共享内存} procedure CloseMap; begin if PShare <> nil then begin {从进程的地址空间中撤销映像文件} UnmapViewOfFile(PShare); end; if HMapping <> 0 then begin {关闭映像文件} CloseHandle(HMapping); end; end; {建立互斥对象} function LockMap: Boolean; begin Result := True; HMapMutex := CreateMutex(nil, False, PChar('My MUTEX NAME COES HERE')); if HMapMutex = 0 then begin ShowMessage('不能创建互斥对象'); Result := False; end else begin if WaitForSingleObject(HMapMutex, REQUEST_TIME_OUT) = WAIT_FAILED then begin ShowMessage('不能对互斥对象枷锁'); Result := False; end; end; end; procedure UnlockMAP(); begin {释放、关闭互斥对象} ReleaseMutex(HMapMutex); CloseHandle(HMapMutex); end; procedure TForm1.btn1Click(Sender: TObject); var str: PChar; begin str := PChar('简单的共享内存示例'); //把数据拷贝到共享内存 CopyMemory(@(pshare^.Data), str, Length(str)*SizeOf(Char)); //发送消息表明有数据 PostMessage(FindWindowW(nil, 'Form2'), WM_DATA, 1, 2); end; procedure TForm1.FormCreate(Sender: TObject); begin OpenMap(); LockMap(); end; procedure TForm1.FormDestroy(Sender: TObject); begin UnlockMAP(); CloseMap(); end; end. 【Delphi下深入Windows编程】一书中CopyMemory使用的长度是Length(str),但是在Delphi增加了Unicode字符支持以后这样会导致长度计算不够,只发送半截字符参考万一的博客中用ByteLength函数解决,但是也有人说,ByteLength函数只能对Unicode字符串求字节长度,如果要对Ansi字符串进行计算,那么结果会是正确值的两倍最终解决方案:Length(str)*SizeOf(Char)接收数据端
unit Unit2; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; const //自定义消息 WM_DATA = WM_USER + 1024; type PShareMem = ^TPShareMem; TPShareMem = record //共享数据 注意要与发送数据段的定义相同 Data: array[0..255] of Char; end; type TForm2 = class(TForm) mmo1: TMemo; btn1: TButton; procedure FormCreate(Sender: TObject); procedure btn1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure getShareInfo(var Msg: TMessage); message WM_DATA; end; var Form2: TForm2; PShare: PShareMem; MapHandle: THandle; implementation {$R *.dfm} { TForm2 } {处理wm_data 自定义消息} procedure TForm2.btn1Click(Sender: TObject); begin CloseHandle(MapHandle); end; procedure TForm2.FormCreate(Sender: TObject); begin MapHandle := OpenFileMapping(FILE_MAP_WRITE, False, PChar('MapName')); if MapHandle = 0 then begin ShowMessage('不能定位内存映像文件块'); 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(TPShareMem), 0); end; procedure TForm2.getShareInfo(var Msg: TMessage); begin {如果是发送数据端发过来的参数是1} if Msg.LParam = 2 then begin //显示共享内存中的数据 mmo1.Text := PShare^.Data; 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(TPShareMem), 0); end; end.转载于:https://www.cnblogs.com/coder163/p/9150598.html
