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.

 

内存映射实现进程通讯_内存映射文件