内存映射实现进程通讯

unit FileMap;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, Dialogs;

type
  //定义TFileMap类
  TFileMap = class(TComponent)
  private
    FMapHandle: THandle; //内存映射文件句柄
    FMutexHandle: THandle; //互斥句柄
    FMapName: string; //内存映射对象
    FSynchMessage: string; //同步信息
    FMapStrings: TStringList; //存储映射文件信息
    FSize: DWord; //映射文件大小
    FMessageID: DWord; //注册的消息号
    FMapPointer: PChar; //映射文件的数据区指针
    FLocked: Boolean; //锁定
    FIsMapOpen: Boolean; //文件是否打开
    FExistsAlready: Boolean; //表示是否已经建立文件映射了
    FReading: Boolean; //正在读取内存映射文件数据
    FAutoSynch: Boolean; //是否自动同步
    FOnChange: TNotifyEvent; //当内存数据区内容改变时
    FFormHandle: Hwnd; //存储本窗口的窗口句柄
    FPNewWndHandler: Pointer; //
    FPOldWndHandler: Pointer; //
    procedure SetMapName(Value: string);
    procedure SetMapStrings(Value: TStringList);
    procedure SetSize(Value: DWord);
    procedure SetAutoSynch(Value: Boolean);
    procedure EnterCriticalSection;
    procedure LeaveCriticalSection;
    procedure MapStringsChange(Sender: TObject);
    procedure NewWndProc(var FMessage: TMessage);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure OpenMap;
    procedure CloseMap;
    procedure ReadMap;
    procedure WriteMap;
    property ExistsAlready: Boolean read FExistsAlready;
    property IsMapOpen: Boolean read FIsMapOpen;
  published
    property MaxSize: DWord read FSize write SetSize;
    property AutoSynchronize: Boolean read FAutoSynch write SetAutoSynch;
    property MapName: string read FMapName write SetMapName;
    property MapStrings: TStringList read FMapStrings write SetMapStrings;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

implementation

//构造函数
constructor TFileMap.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAutoSynch := True;
  FSize := 4096;
  FReading := False;
  FMapStrings := TStringList.Create;
  FMapStrings.OnChange := MapStringsChange;
  FMapName := ‘Unique & Common name‘;
  FSynchMessage := FMapName + ‘Synch-Now‘;
  if AOwner is TForm then
  begin
    FFormHandle := (AOwner as TForm).Handle;
    //得到窗口处理过程的地址
    FPOldWndHandler := Ptr(GetWindowLong(FFormHandle, GWL_WNDPROC));
    FPNewWndHandler := MakeObjectInstance(NewWndProc);
    if FPNewWndHandler = nil then
      raise Exception.Create(‘超出资源‘);
    //设置窗口处理过程新的地址
    SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPNewWndHandler));
  end
  else raise Exception.Create(‘组件的所有者应该是TForm‘);
end;

//析构函数
destructor TFileMap.Destroy;
begin
  CloseMap;
  //还原Windows处理过程地址
  SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPOldWndHandler));
  if FPNewWndHandler <> nil then
    FreeObjectInstance(FPNewWndHandler);
  //释放对象
  FMapStrings.Free;
  FMapStrings := nil;
  inherited destroy;
end;

//打开文件映射,并映射到进程空间
procedure TFileMap.OpenMap;
var
  TempMessage: array[0..255] of Char;
begin
  if (FMapHandle = 0) and (FMapPointer = nil) then
  begin
    FExistsAlready := False;
      // 创建文件映射对象
    FMapHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, FSize, PChar(FMapName));
    if (FMapHandle = INVALID_HANDLE_VALUE) or (FMapHandle = 0) then
      raise Exception.Create(‘创建文件映射对象失败!‘)
    else
    begin
   //判断是否已经建立文件映射了
      if (FMapHandle <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then
        FExistsAlready := True; //如果已建立的话,就设它为True
    //映射文件的视图到进程的地址空间
      FMapPointer := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      if FMapPointer = nil then
        raise Exception.Create(‘映射文件的视图到进程的地址空间失败‘)
      else
      begin
        StrPCopy(TempMessage, FSynchMessage);
      //在Windows中注册消息常量
        FMessageID := RegisterWindowMessage(TempMessage);
        if FMessageID = 0 then
          raise Exception.Create(‘注册消息失败‘)
      end
    end;
      //创建互斥对象,在写文件映射空间时,用到它,以保持数据同步
    FMutexHandle := Windows.CreateMutex(nil, False, PChar(FMapName + ‘.Mtx‘));
    if FMutexHandle = 0 then
      raise Exception.Create(‘创建互斥对象失败‘);
    FIsMapOpen := True;
    if FExistsAlready then //判断内存文件映射是否已打开
      ReadMap
    else
      WriteMap;
  end;
end;

//解除文件视图和内存映射空间的关系,并关闭文件映射
procedure TFileMap.CloseMap;
begin
  if FIsMapOpen then
  begin
    //释放互斥对象
    if FMutexHandle <> 0 then
    begin
      CloseHandle(FMutexHandle);
      FMutexHandle := 0;
    end;
    //关闭内存对象
    if FMapPointer <> nil then
    begin
   //解除文件视图和内存映射空间的关系
      UnMapViewOfFile(FMapPointer);
      FMapPointer := nil;
    end;
    if FMapHandle <> 0 then
    begin
    //并关闭文件映射
      CloseHandle(FMapHandle);
      FMapHandle := 0;
    end;
    FIsMapOpen := False;
  end;
end;

//读取内存文件映射内容
procedure TFileMap.ReadMap;
begin
  FReading := True;
  if (FMapPointer <> nil) then FMapStrings.SetText(FMapPointer);
  FReading := False;
end;

//向内存映射文件里写
procedure TFileMap.WriteMap;
var
  StringsPointer: PChar;
  HandleCounter: integer;
  SendToHandle: HWnd;
begin
  if FMapPointer <> nil then
  begin
    StringsPointer := FMapStrings.GetText;
    //进入互斥状态,防止其他线程进入同步区域代码
    EnterCriticalSection;
    if StrLen(StringsPointer) + 1 <= FSize
      then System.Move(StringsPointer^, FMapPointer^, StrLen(StringsPointer) + 1)
    else
      raise Exception.Create(‘写字符串失败,字符串太大!‘);
    //离开互斥状态
    LeaveCriticalSection;
    //广播消息,表示内存映射文件内容已修改
    SendMessage(HWND_BROADCAST, FMessageID, FFormHandle, 0);
    //释放StringsPointer
    StrDispose(StringsPointer);
  end;
end;

//当MapStrins值改变时
procedure TFileMap.MapStringsChange(Sender: TObject);
begin
  if FReading and Assigned(FOnChange) then
    FOnChange(Self)
  else if (not FReading) and FIsMapOpen and FAutoSynch then
    WriteMap;
end;

//设置MapName属性值
procedure TFileMap.SetMapName(Value: string);
begin
  if (FMapName <> Value) and (FMapHandle = 0) and (Length(Value) < 246) then
  begin
    FMapName := Value;
    FSynchMessage := FMapName + ‘Synch-Now‘;
  end;
end;

//设置MapStrings属性值
procedure TFileMap.SetMapStrings(Value: TStringList);
begin
  if Value.Text <> FMapStrings.Text then
  begin
    if Length(Value.Text) <= FSize then
      FMapStrings.Assign(Value)
    else
      raise Exception.Create(‘写入值太大‘);
  end;
end;

//设置内存文件大小
procedure TFileMap.SetSize(Value: DWord);
var
  StringsPointer: PChar;
begin
  if (FSize <> Value) and (FMapHandle = 0) then
  begin
    StringsPointer := FMapStrings.GetText;
    if (Value < StrLen(StringsPointer) + 1) then
      FSize := StrLen(StringsPointer) + 1
    else FSize := Value;
    if FSize < 32 then FSize := 32;
    StrDispose(StringsPointer);
  end;
end;

//设置是否同步
procedure TFileMap.SetAutoSynch(Value: Boolean);
begin
  if FAutoSynch <> Value then
  begin
    FAutoSynch := Value;
    if FAutoSynch and FIsMapOpen then WriteMap;
  end;
end;

//进入互斥,使得被同步的代码不能被别的线程访问
procedure TFileMap.EnterCriticalSection;
begin
  if (FMutexHandle <> 0) and not FLocked then
  begin
    FLocked := (WaitForSingleObject(FMutexHandle, INFINITE) = WAIT_OBJECT_0);
  end;
end;

//解除互斥关系,可以进入保护的同步代码区
procedure TFileMap.LeaveCriticalSection;
begin
  if (FMutexHandle <> 0) and FLocked then
  begin
    ReleaseMutex(FMutexHandle);
    FLocked := False;
  end;
end;

//消息捕获过程
procedure TFileMap.NewWndProc(var FMessage: TMessage);
begin
  with FMessage do
  begin
    if FIsMapOpen then //内存文件打开
   {如果消息是FMessageID,且WParam不是FFormHandle,就调用ReadMap,
    去读取内存映射文件的内容,表示内存映射文件的内容已变}
      if (Msg = FMessageID) and (WParam <> FFormHandle) then
        ReadMap;
    Result := CallWindowProc(FPOldWndHandler, FFormHandle, Msg, wParam, lParam);
  end;
end;

end.

unit MainFrm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, FileMap;

type
  TfrmMain = class(TForm)
    btnWriteMap: TButton;
    btnReadMap: TButton;
    btnClear: TButton;
    chkExistsAlready: TCheckBox;
    chkIsMapOpen: TCheckBox;
    btnOpenMap: TButton;
    btnCloseMap: TButton;
    mmoCont: TMemo;
    chkAutoSynchronize: TCheckBox;
    Label5: TLabel;
    lblHelp: TLabel;
    procedure btnWriteMapClick(Sender: TObject);
    procedure btnReadMapClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure btnOpenMapClick(Sender: TObject);
    procedure btnCloseMapClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure chkAutoSynchronizeClick(Sender: TObject);
    procedure mmoContKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    //定义TFileMap的对象
    FileMap: TFileMap;
    //定义FileMapChange用于赋给FileMap的OnChange事件
    procedure FileMapChange(Sender: TObject);
    procedure Check;
   { Private declarations }
  public
  { Public declarations }
  end;

var
  frmMain: TfrmMain;
implementation

{$R *.DFM}

//检查FileMap的ExistsAlready和IsMapOpen属性
procedure TfrmMain.Check;
begin
  chkExistsAlready.Checked := FileMap.ExistsAlready;
  chkIsMapOpen.Checked := FileMap.IsMapOpen;
end;

//在窗体创建时,初始化FileMap对象
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  //创建对象FileMap
  FileMap := TFileMap.Create(self);
  FileMap.OnChange := FileMapchange;
  chkAutoSynchronize.Checked := FileMap.AutoSynchronize;
  //如果内存对象还未创建,初始化FileMap里的内容
  if not FileMap.ExistsAlready then
  begin
    MmoCont.Lines.LoadFromFile(‘Project1.dpr‘);
    FileMap.MapStrings.Assign(MmoCont.Lines);
  end;
  lblHelp.Caption := ‘使用说明:运行两个或多个此应用程序,按下“打开内存映射”按钮,‘
    + #13 + ‘选中“是否同步”复选框,在备注框里改动,在另外的应用程序中将会‘
    + #13 + ‘该动后的信息,同时也可以读写数据按钮来获取共享信息‘
end;

//写入内存文件映射的数据
procedure TfrmMain.btnWriteMapClick(Sender: TObject);
begin
  FileMap.WriteMap;
end;

//读取内存文件映射的数据
procedure TfrmMain.btnReadMapClick(Sender: TObject);
begin
  FileMap.ReadMap;
end;

//清除内存文件数据
procedure TfrmMain.btnClearClick(Sender: TObject);
begin
  Mmocont.Clear;
  FileMap.MapStrings.Clear;
  check;
end;

//打开内存文件映射
procedure TfrmMain.btnOpenMapClick(Sender: TObject);
begin
  FileMap.MapName := ‘Delphi 6 ‘;
  FileMap.OpenMap;
  check;
end;

//关闭内存映射
procedure TfrmMain.btnCloseMapClick(Sender: TObject);
begin
  FileMap.CloseMap;
  Check;
end;

//当内存映射文件的数据改变时,显示最新数据
procedure TfrmMain.FileMapChange(Sender: TObject);
begin
  Mmocont.Lines.Assign(FileMap.MapStrings);
  Check;
end;

//设置是否同步显示
procedure TfrmMain.chkAutoSynchronizeClick(Sender: TObject);
begin
  FileMap.AutoSynchronize := chkAutoSynchronize.Checked;
end;

//在备注框里写时,同时更新进内存映射文件
procedure TfrmMain.mmoContKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  FileMap.MapStrings.Assign(MmoCont.Lines);
end;

end.

http://blog.csdn.net/zang141588761/article/details/52062603

时间: 2024-10-06 13:44:06

内存映射实现进程通讯的相关文章

利用内存映射文件在两个进程间共享数据 转

private hMapFile: THandle; MapFilePointer: Pointer; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin hMapFile := CreateFileMapping ( $FFFFFFFF, // 特殊内存映射句柄 nil, page_

使用内存映射开发高性能进程间消息通信组件

一.背景 项目开发中免不了各模块或系统之间进行消息通信,目前热门的消息中间件有Redis.RabbitMQ.Kafka.RocketMQ等等. 以上几种组件中Redis在消息队列方面表现还可以,但是如果涉及发布订阅功能,就不行了,最近项目就使用了redis的发布订阅, 每秒只能发出几千条,虽然目前绰绰有余,但是瓶颈可以预期. 其余的几种都是比较重量级的消息中间件,什么跨平台.分布式.集群.支持N种协议等等,很高大全, 我们可能就只使用了其中1.2个功能.严格来说,项目中集成这几种MQ的工作量是不

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转

原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它. 内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作.物理存储是文件管理,而内存

内存映射机制

http://www.lxway.com/956280826.htm 当CPU读取数据时,是由内存管理单元(MMU)管理的.MMU位于CPU与物理内存之间,它包含从虚拟地址向物理内存地址转化的映射信息.当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号. 当某个进程读取磁盘上的数据时,进程要求其缓冲通过read()系统调用填满,这个系统调用导致内核向磁盘控制硬件发出一条命令要从磁盘获取数据.磁盘控制器通过DMA直接将数据写入内核的内存

C#内存映射文件学习[转]

原文链接 内存映射文件是由一个文件到进程地址空间的映射. C#提供了允许应用程序把文件映射到一个进程的函(MemoryMappedFile.CreateOrOpen).内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存.由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它. 内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作.物理存储是文件管理,而内存映射文件是操作系统级内存管理. 优势:     1.访问磁盘文件上的数据不需执行I/O操作和缓存

JAVA NIO 内存映射(转载)

原文地址:http://blog.csdn.net/fcbayernmunchen/article/details/8635427 Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数 read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当

内存映射文件

一段内存地址空间,映射着物理存储器上一个已经存在于磁盘上的文件.在对该文件进行操作之前必须首先对文件进行映射.使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作. 内存映射文件,是由一个文件到一块内存的映射.Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping). API: HANDLE CreateFileMapping(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttribute

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动)

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动) 2015-02-22 李海沿 刚刚我们实现了linux系统内存的分配,读写,释放功能,下面,我们一鼓作气将IO端口映射及IO内存映射搞定,加油! (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存.BIOS等).在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址