分享
 
 
 

映射文件的使用

王朝other·作者佚名  2006-09-16
窄屏简体版  字體: |||超大  

在WIN32种,通过使用映像文件在进程间实现共享文件或内存共享,如果利用相同的映像名字或文件句柄,则不同的进程可以通过一个指针来读写同一个文件或者同一内存数据块,并把他们当成该进程内存空间的一部分。

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

映像文件的另一个重要作用就是用来支持永久命名的共享内存。要在两个应用程序之间共享内存,可以在一个应用程序中创建一个文件并映射,然后另外一个程序通过打开和映射此文件,并把它当作自己进程的内存来使用。事实上,此内存是所有进程共享的。

下面将先描述一下几个操作内存的API函数

1、创建内存映射的API函数

This function creates a named or unnamed file-mapping object for the specified file.

HANDLE CreateFileMapping(

//通过调用fileopen or FileCreate后返回的文件句柄,如果是内存,则//$FFFFFFFF

HANDLE hFile,

//安全性结构,一般null

LPSECURITY_ATTRIBUTES lpFileMappingAttributes,

//文件试图的保护类型,PAGE_READONLY,PAGE_READWRITE,

DWORD flProtect,

//文件大小的高32位,一般设置为0,除非文件大于4G

DWORD dwMaximumSizeHigh,

//文件大小低32位

DWORD dwMaximumSizeLow,

//映射的名字

LPCTSTR lpName

);

2、打开一个映射文件

HANDLE OpenFileMapping(

//访问数据模式:FILE_MAP_ALL_ACCESS,FILE_MAP_COPY,FILE_MAP_READ, //FILE_MAP_WRITE

DWORD dwDesiredAccess,

//子进程是否可以继承

BOOL bInheritHandle,

//映射文件名

LPCTSTR lpName

);

3、将映射文件映射到本进程的API函数

LPVOID MapViewOfFile(

//通过CreateFileMapping或OpenFileMapping返回的文件句柄

HANDLE hFileMappingObject,

//访问的数据模式:FILE_MAP_WRITE,FILE_MAP_READ,FILE_MAP_ALL_ACCESS

DWORD dwDesiredAccess,

//指定数据在映射文件中起始位置的高32位

DWORD dwFileOffsetHigh,

//低32位

DWORD dwFileOffsetLow,

//需要映射的大小,0表示全部

DWORD dwNumberOfBytesToMap

);

4、关闭映射的api函数

BOOL UnmapViewOfFile(

//由MapViewofFile产生的映射文件的地址

LPCVOID lpBaseAddress

);

5、下面例子中还会用到的几个api函数

创建互斥对象

HANDLE WINAPI CreateMutex(

LPSECURITY_ATTRIBUTES lpMutexAttributes,

BOOL bInitialOwner,

LPCTSTR lpName

);

DWORD WaitForSingleObject(

HANDLE hHandle,

DWORD dwMilliseconds

);

上文中曾经提到我们使用内存映射的方式来在多个程序或DLL中共享数据。下面就通过一个程序来介绍。

虽然我要描述的是再两个应用程序之间共享数据,不过为了省事,我将所有的内容都写在一个程序中,你只需要把此程序打开两次就可以了。一个程序用来建立内存映射文件,另外一个程序用来打开内存映射文件。并通过对公共内存的读写操作来演示信息共享。

程序的窗体单元代码如下:

object Form1: TForm1

Left = 236

Top = 147

Width = 327

Height = 412

Caption = 'MyMapForm_1'

Color = clBtnFace

Font.Charset = ANSI_CHARSET

Font.Color = clWindowText

Font.Height = -13

Font.Name = '宋体'

Font.Style = []

OldCreateOrder = False

OnClose = FormClose

OnCreate = FormCreate

PixelsPerInch = 96

TextHeight = 13

object GroupBox1: TGroupBox

Left = 0

Top = 0

Width = 319

Height = 121

Align = alTop

Caption = '共享内存的信息[发送]'

TabOrder = 0

object Label1: TLabel

Left = 16

Top = 24

Width = 26

Height = 13

Caption = '数据'

end

object Label2: TLabel

Left = 16

Top = 48

Width = 39

Height = 13

Caption = '修改者'

end

object Label3: TLabel

Left = 16

Top = 80

Width = 52

Height = 13

Caption = '修改时间'

end

object edData: TEdit

Left = 75

Top = 21

Width = 230

Height = 21

TabOrder = 0

end

object edModifyUser: TEdit

Left = 74

Top = 49

Width = 231

Height = 21

TabOrder = 1

end

object edModifyTime: TEdit

Left = 74

Top = 73

Width = 231

Height = 21

Enabled = False

TabOrder = 2

end

end

object Panel1: TPanel

Left = 0

Top = 242

Width = 319

Height = 121

Align = alClient

BevelOuter = bvNone

TabOrder = 1

object btnCreate: TButton

Left = 32

Top = 8

Width = 113

Height = 25

Caption = '新建内存映射'

TabOrder = 0

OnClick = btnCreateClick

end

object btnOpen: TButton

Left = 160

Top = 8

Width = 113

Height = 25

Caption = '打开已存在映射'

TabOrder = 1

OnClick = btnOpenClick

end

object btnRead: TButton

Left = 160

Top = 45

Width = 113

Height = 25

Caption = '读取映射信息'

TabOrder = 2

OnClick = btnReadClick

end

object btnSet: TButton

Left = 32

Top = 45

Width = 113

Height = 25

Caption = '设置内存信息'

TabOrder = 3

OnClick = btnSetClick

end

object btnClose: TButton

Left = 32

Top = 85

Width = 113

Height = 25

Caption = '关闭映射'

TabOrder = 4

OnClick = btnCloseClick

end

object btnClear: TButton

Left = 160

Top = 85

Width = 113

Height = 25

Caption = '清空编辑狂'

TabOrder = 5

OnClick = btnClearClick

end

end

object StatusBar1: TStatusBar

Left = 0

Top = 363

Width = 319

Height = 19

Panels = <

item

Width = 200

end>

end

object GroupBox2: TGroupBox

Left = 0

Top = 121

Width = 319

Height = 121

Align = alTop

Caption = '共享内存的信息[接收]'

Enabled = False

TabOrder = 3

object Label4: TLabel

Left = 16

Top = 24

Width = 26

Height = 13

Caption = '数据'

end

object Label5: TLabel

Left = 16

Top = 48

Width = 39

Height = 13

Caption = '修改者'

end

object Label6: TLabel

Left = 16

Top = 80

Width = 52

Height = 13

Caption = '修改时间'

end

object edRData: TEdit

Left = 75

Top = 21

Width = 230

Height = 21

TabOrder = 0

end

object edRUser: TEdit

Left = 74

Top = 49

Width = 231

Height = 21

TabOrder = 1

end

object edRTime: TEdit

Left = 74

Top = 73

Width = 231

Height = 21

Enabled = False

TabOrder = 2

end

end

end

程序的代码主要分为两部分,comm.pas单元中定义几个对操作内存映射的函数,以及共享内存的结构信息。代码如下:

...{

作者: wudi_1982

联系方式: wudi_1982@hotmail.com

开发工具以及平台:DELPHI7+WINXP

转载请注明出处

}

unit comm;

interface

uses

Windows,SysUtils;

const

FILEMAPPINGNAME = 'MyFileMapping'; // 指定内存映射的名字

MUTEXNAME= 'MutexName'; //互斥对象的名字

type

TShareMem = record //共享内存的结构信息

Data : array[0..255] of char; //描述共享数据信息

ModifyUser : array[0..255] of char; //对数据的修改者

ModifyTime : array[0..7] of char; //数据最近一次的修改时间

end;

PShareMem = ^TShareMem;

var

FileMapHandle : THandle; //建立映射的句柄

MutexHandle : THandle; // 互斥对象的句柄

ShareMem : PShareMem; //一个指向共享内存的指针

function OpenMap:THandle; //打开一个映射文件并映射到本进程中

function CreateMap:THandle; //新建一个映射文件并映射到本进程中

function LockMap:boolean; //加锁

procedure UnLockMap; //解锁

procedure CloseMap; //关闭映射

function ReadCommData:TShareMem; //从共享信息中读取数据

procedure WriteCommData(data,user,time : string);//对共享内存进行写操作

implementation

function OpenMap:THandle;

begin

//打开映射文件

FileMapHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, //所有权限

false, //子进程不可继承

FILEMAPPINGNAME

);

if FileMapHandle <> 0 then //如果映射文件打开成功

begin

//将映射文件映射到本进程

ShareMem := pSharemem(MapViewOfFile(FileMapHandle,FILE_MAP_ALL_ACCESS,0,0,0));

if ShareMem = nil then

begin

CloseHandle(FileMapHandle);

Result := 0;

end else begin

//初始化共享区域

FillChar(ShareMem^,sizeof(TSharemem),0);

Result := FileMapHandle;

end;

end else Result := 0;

end;

function CreateMap:THandle;

begin

FileMapHandle := CreateFileMapping($FFFFFFFF,//内存映射

nil,

PAGE_READWRITE,//读写操作

0,//高32位 ,一般为0,除非要映射的文件大于4G

sizeof(TShareMem),

FILEMAPPINGNAME

);

if FileMapHandle <> 0 then

begin

ShareMem := pSharemem(MapViewOfFile(FileMapHandle,FILE_MAP_ALL_ACCESS,0,0,0));

if ShareMem = nil then

begin

CloseHandle(FileMapHandle);

Result := 0;

end else Result := FileMapHandle;

end else Result := 0;

end;

function LockMap:boolean;

begin

//创建一个互斥对象并加锁

MutexHandle := CreateMutex(nil,false,MUTEXNAME);

if MutexHandle <> 0 then

begin

if WaitForSingleObject(MutexHandle,1000)= WAIT_FAILED then Result := false

else Result := true;

end else Result := false;

end;

procedure UnLockMap;

begin

//释放资源

if MutexHandle <> 0 then

begin

ReleaseMutex(MutexHandle);

CloseHandle(MutexHandle);

end;

end;

procedure CloseMap;

begin

// 关闭映射并释放资源

if ShareMem <> nil then UnmapViewOfFile(ShareMem);

if FileMapHandle <> 0 then CloseHandle(FileMapHandle);

end;

function ReadCommData:TShareMem;

var

tm : TShareMem;

begin

with tm do

begin

Data := ShareMem^.Data;

ModifyUser := ShareMem^.ModifyUser;

ModifyTime := ShareMem^.ModifyTime;

end;

Result := tm;

end;

procedure WriteCommData(data,user,time : string);

begin

StrCopy(ShareMem^.Data,pchar(data));

StrCopy(ShareMem^.ModifyUser,pchar(user));

StrCopy(ShareMem^.ModifyTime,pchar(time));

end;

end.

代码的另一个部分就是根据需要调用这些函数的FirstTest.pas,即上面窗体单元对应的代码

...{

作者: wudi_1982

联系方式: wudi_1982@hotmail.com

开发工具以及平台:DELPHI7+WINXP

转载请注明出处

}

unit FirstTest;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, ComCtrls, ExtCtrls;

const

WM_MYMESSAGE=WM_USER+1024; //一个自定义消息,用来通知接受程序数据到达

type

TForm1 = class(TForm)

GroupBox1: TGroupBox;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

edData: TEdit;

edModifyUser: TEdit;

edModifyTime: TEdit;

Panel1: TPanel;

btnCreate: TButton;

btnOpen: TButton;

btnRead: TButton;

btnSet: TButton;

btnClose: TButton;

btnClear: TButton;

StatusBar1: TStatusBar;

GroupBox2: TGroupBox;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

edRData: TEdit;

edRUser: TEdit;

edRTime: TEdit;

procedure btnCreateClick(Sender: TObject);

procedure btnOpenClick(Sender: TObject);

procedure btnSetClick(Sender: TObject);

procedure btnCloseClick(Sender: TObject);

procedure btnReadClick(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure btnClearClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

private

atm : TAtom; //一个原子

nextwindow : string; //被发送消息程序的标题信息

procedure MyMessage(var msg : TMessage);message WM_MYMESSAGE; //自定义消息的处理

public

end;

var

Form1: TForm1;

implementation

uses comm;

...{$R *.dfm}

procedure TForm1.btnCreateClick(Sender: TObject);

begin

if CreateMap = 0 then

ShowMessage('内存映射建立失败')

else begin

btnCreate.Enabled := false;

btnOpen.Enabled := false;

StatusBar1.Panels[0].Text := '内存映射文件新建立完毕'

end;

end;

procedure TForm1.btnOpenClick(Sender: TObject);

begin

if OpenMap = 0 then

ShowMessage('内存映射打开失败')

else begin

btnCreate.Enabled := false;

btnOpen.Enabled := false;

StatusBar1.Panels[0].Text := '内存映射文件打开完毕'

end;

end;

procedure TForm1.btnSetClick(Sender: TObject);

var

hd : THandle;

begin

if (edData.Text = '') or (edModifyUser.Text = '') then

ShowMessage('请填写完整信息')

else begin

edModifyTime.Text := FormatDateTime('mm:hh:mm',Now);

WriteCommData(edData.Text,edModifyUser.Text,edModifyTime.Text);

//查找此程序的另外一个实例,如果找到,发送数据到达的消息

hd := FindWindow(nil,pchar(nextwindow));

if hd <> 0 then

SendMessage(hd,WM_MYMESSAGE,1,0);

end;

end;

procedure TForm1.btnCloseClick(Sender: TObject);

begin

UnLockMap;

CloseMap;

btnCreate.Enabled := true;

btnOpen.Enabled := true;

end;

procedure TForm1.btnReadClick(Sender: TObject);

var

tm : TShareMem;

begin

tm := ReadCommData;

edRData.Text := tm.Data;

edRUser.Text := tm.ModifyUser;

edrTime.Text := tm.ModifyTime;

end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

UnLockMap;

CloseMap;

//下面这一句非常重要,如果不及时删除原子表中添加的原子,

//怕是只有重启计算机才能干掉程序启动时添加到原子表中的信息了

GlobalDeleteAtom(atm);

end;

procedure TForm1.btnClearClick(Sender: TObject);

begin

edData.Text := '';

edModifyUser.Text := '';

edModifyTime.Text := '';

end;

procedure TForm1.MyMessage(var msg: TMessage);

begin

if msg.WParam = 1 then

begin

Application.BringToFront;

StatusBar1.Panels[0].Text := '新数据到代';

btnReadClick(nil);

end;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

//下面的代码将在程序启动时执行,主要是通过原子表检查此程序是否运行,

//本程序运行运行两个实例,一个用来建立映射文件,

//一个用来打开映射文件,你完全可以用两个不同的程序来处理,这里为了方便

//以及演示原子表的使用而采用一个程序执行两次的方法来做

if GlobalFindAtom(pchar('wudi_1982')) <> 0 then//查找原子表如果第一个窗体已经存在

begin

if GlobalFindAtom(pchar('jingyang')) <> 0 then//如果第二个窗体也存在

begin

Application.Terminate;

end else begin

//添加原子到原子表,以记录此程序的第二个实例已经运行,并做相应操作

atm := GlobalAddAtom(pchar('jingyang'));

Application.Title := 'MyMapForm_2';

Form1.Caption := 'MyMapForm_2';

nextwindow := 'MyMapForm_1';

end;

end else begin

//添加原子到原子表,以记录此程序的第一个实例已经运行,并做相应操作

atm := GlobalAddAtom(pchar('wudi_1982'));

Application.Title := 'MyMapForm_1';

Form1.Caption := 'MyMapForm_1';

nextwindow := 'MyMapForm_2';

end;

end;

end.

程序运行效果图:

例程的使用方法:

编译之后,运行此程序的两个实例,在其中一个实例中,点击按钮【新建内存映射】,另一个实例使用【打开已存在的映射】,然后在窗体的发送部分,填写相应信息,然后点击【设计内存信息】,就可以看到效果了。

注:WINXP+D7;

转载请注明出处

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有