zoukankan      html  css  js  c++  java
  • 进程间的数据共享

    1. 概述

    在win32中,通过使用映像文件在进程间实现共享文件或共享内存数据块,如果利用相同的映像名字或文件句柄,则不同的进程可以通过一个指针来读写一个文件或同一个内存数据块,并把它当做该进程内地址空间的一部分

    在Windows9x/NT/200 向内存中装载文件时,使用了特殊的全局内存区。在该区域内,应用程序的虚拟内存地址和文件中的响应位置对应,由于所有进程恭喜了一个用于存储映像文件的全局内存区域,因而当两个进程装载相同模块(应用程序exe或dll文件)时,他们实际上是在内存中共享其执行代码

    内存映像文件可以映射一个文件、一个文件中的指定区域或者指定的内存块,其中的数据就可以用内存读写指令直接访问,而不比频繁的调用ReadFile或WriteFIle这样的I/O系统函数,从而提高了文件存取速度和效率

    2. 示例代码

    2.1. 两个exe之间共享数据

    发送数据端

    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.
    
    
  • 相关阅读:
    [BZOJ 3774] 最优选择 【最小割】
    [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】
    [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】
    [XJOI NOI2015模拟题13] B 最小公倍数 【找规律】
    [XJOI NOI2015模拟题13] A 神奇的矩阵 【分块】
    [XJOI NOI02015训练题7] B 线线线 【二分】
    Java+Maven+selenium+testng+reportng自动化测试框架
    selenium实例:unittest框架+PO开发模式
    WebDriver驱动下载地址
    testng 执行多个suite
  • 原文地址:https://www.cnblogs.com/coder163/p/9150598.html
Copyright © 2011-2022 走看看