请教, 关于 CreateFileMapping 和 MapViewOfFile 的用法 ( 积分: 50 )

  • 主题发起人 主题发起人 SuKiDelphi
  • 开始时间 开始时间
S

SuKiDelphi

Unregistered / Unconfirmed
GUEST, unregistred user!
我想在二个程序(A 和 B)中共享数据,但总不成功, 请大家来指点一下
//程序 A :

type
TData = record
StrA : String;
IntA, IntB :Integer;
end;
PData=^TData;

var //全局
DLLData : PData;


procedure TFormA.FormCreate(Sender: TObject);
var FHandle: LongWORD;
begin
New(DLLData);
FHandle:=CreateFileMapping($FFFFFFFF, // 文件句柄
nil, // 可选安全属性
PAGE_READWRITE, // 映象文件保护方式
0,
$ffff,
'SuKiDelphi'); // 映象文件的名字
if FHandle > 0 then
begin
FHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'SuKiDelphi');
DLLData:=MapViewOfFile(FHandle,FILE_MAP_ALL_ACCESS, 0, 0, 0);
end;
end;


//程序 B :
type
TData = record
StrA : String;
IntA, IntB :Integer;
end;
PData=^TData;

var //全局
DLLData : PData;


procedure TFormB.FormCreate(Sender: TObject);
var FHandle: LongWORD;
S : String;
begin
New(DLLData);
FHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'SuKiDelphi');
DLLData:=MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
CloseHandle(FHandle);
S:=DLLData^.StrA;
Edit1.Text:=S;
end;

上面的代码在运行时总是出错!!!
 
function CreateFileMapping(
hFile:THandle;//调用FileOpen(),FileCreate()函数返回的文件句柄.
lpFileMappingAttributes:PSecurityAttributes;//指向文件映射对象的安全属性结构,通常为0.
flProtect, //指定文件视图的保护模式(PAGE_READONLY文件可读,PAGE_READWRITE 文件可读写,PAGE_WRITECOPY 文件可读写).
dwMaximumSizeHigh, //指定文件映射对象的最大尺寸的高32位
dwMaximumSizeLow:DWORD; //指定文件映射对象的最大尺寸的低32位
lpName:PChar//指定文件映射对象名称.
):THandle;
function MapViewOfFile(
hFileMappingObject:THandle;//通过CreateFileMapping()或OpenFileMapping()返回的文件映射对象的句柄.
dwDesiredAccess:DWORD;//指定访问文件数据的模式
//(FILE_MAP_WRITE,FILE_MAP_READ,FILE_MAP_COPY)
dwFileOffsetHigh,//指定文件映射起始位置的高32位
dwFileOffsetLow,//指定文件映射起始位置的低32位
dwNumberOfBytesToMap:DWORD//指定文件映射需要的字节数
):Pointer;
 
try
New(DLLData);
FHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'SuKiDelphi');
DLLData:=MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if DLLData = NIL THEN
raise Exception.Create('Failed to map view of file');
finally
CloseHandle(FHandle);
end;
try
S:=DLLData^.StrA;
Edit1.Text:=S;
finally
UnampViewOfFile(DLLData);
end;
跟踪一下....
 
谢谢
但还是:

//------------------------------------------------------------------------------

//程序 A :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TData = record
StrA : String;
IntA, IntB :Integer;
end;
PData=^TData;




type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
DLLData : PData;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

var FHandle: LongWORD;
begin
New(DLLData);
DLLData^.StrA:='11111111';
DLLData^.IntA:=1;
DLLData^.IntB:=2;
FHandle:=CreateFileMapping($FFFFFFFF, // 文件句柄
nil, // 可选安全属性
PAGE_READWRITE, // 映象文件保护方式
0,
$ffff,
'SuKiDelphi'); // 映象文件的名字


end;


//------------------------------------------------------------------------------

//程序 B :
unit Unit1;

interface

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

type
TData = record
StrA : String;
IntA, IntB :Integer;
end;
PData=^TData;


type
TForm1 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
DLLData : PData;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var FHandle: LongWORD;
S : String;
begin
try
New(DLLData);
FHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'SuKiDelphi');
DLLData:=MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if DLLData = NIL THEN
raise Exception.Create('Failed to map view of file');
finally
CloseHandle(FHandle);
end;
try
S:=DLLData^.StrA;
Edit1.Text:=S;
finally
UnmapViewOfFile(DLLData);
end;
end;
end.



结果, 什么也读不出来。。。。请大家再指点一下!!!!!
 
OpenFileMapping改为CreateFileMapping,搞定!
 
结果, 还是什么也读不出来。。。。请大家再指点一下!!!!!
谁能给个例子。。。
 
type
TData = record
//StrA : String;
StrA: array[0..999]of Char;
IntA, IntB :Integer;
...
var d: TData;
ZeroMemory(@d, SizeOf(d));
lstrcpy(@d.StrA[0], 'some string');
...
S:= PChar(@DLLData^.StrA[0]);
 
结果, 还是什么也读不出来。。。。请大家再指点一下!!!!!
谁能给个例子。。。
-------------------------------------------
一、
你在程序A里面什么都没写入,当然什么也读不出来。。。
在程序A中加上下面的试试。
DLLData.StrA:='test';
二、
程序B中的OpenFileMapping还是要改成CreateFileMapping函数,写法与程序A一致,
跨进程共享必须用CreateFileMapping,如果在同一个进程里,则可以用OpenFileMapping。
 
另外,正如TrustMe所述,最好使用定长字符串。如array[0..999]of Char;
 
内存映射的典型应用:
1.在WIN32系统中,利用内存映射文件实现调入和执行.exe和.dll文件.这样就能节省了交换文件的空间,减少了文件调入的时间.
2.利用内存映射文件可以实现多个进程共享数据.//楼主的例子
3.通过一个指向该内存区域的指针,实现对映射文件的数据访问.
提供一个应用例子:
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
UCase := True;
ChangeFileCase;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
UCase :=False;
ChangeFileCase;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.LoadFromFile('FName.txt'); //默认大写
UCase := True;
end;

procedure TForm1.ChangeFileCase;
var
FFileHandle:THandle;//已打开文件的句柄
FMapHandle:THandle;//文件映射对象的句柄
FFileSize:Integer; //文件大小的变量
FData:PByte;
PData:PChar;
begin
if not FileExists('FName.txt') then
raise Exception.Create('File does not exist.')
else
FFileHandle:=FileOpen('FName.txt',fmOpenReadWrite);
if FFileHandle=INVALID_HANDLE_VALUE then
raise Exception.Create('Failed to open or create file');
try
FFileSize:=GetFileSize(FFileHandle,Nil);//获得文件的尺寸
FMapHandle:= CreateFileMapping(FFileHandle,nil,PAGE_READWRITE,0,FFileSize,nil);
if FMapHandle = 0 then
raise Exception.Create('不能创建文件映射');
finally
CloseHandle(FFileHandle);//释放文件句柄
end;
try
FData:=MapViewOfFile(FMapHandle,FILE_MAP_ALL_ACCESS,0,0,FFileSize);
if FData = nil then
raise Exception.Create('Failed to map view of file');
finally
CloseHandle(FMapHandle);
end;
try
{使文件中的所有字符都变为大写}
PData:=PChar(FData);
//将指针定位到文件末尾
inc(PData,FFileSize);
//在文件尾附加一个空结束符
PData^:= #0;
//使所有的字符都变成大写
if UCase then
StrUpper(PChar(FData))
else
StrLower(PChar(FData));
finally
UnmapViewOfFile(FData);//释放文件映射操作
end;
Memo1.Lines.Clear;
Memo1.Lines.LoadFromFile('FName.txt');
end;
 
成功了!!!
多谢大家的热心帮助, 多谢了!!!特别是“smokingroom”和“angellover”的多次热心帮助,本人无以为报,只能愿你们 永远幸福,快乐。
 
如果主程序和DLL都要写入"DLLData", 不知如何改:
主程序:
type
TData = record
IntA, IntB :Integer;
end;
PData=^TData;

var
Form1: TForm1;
FHandle: LongWORD;
DLLData: PData;
function SetDllDate : boolean; stdcall; external 'MYDLL';



//------------------------------------------------------------------------------

procedure TForm1.AppSetting(WriteSet : boolean);
var
TId : DWORD;
begin
// 其它功能的代码...........
直接用"DLLData"
with DLLData^ do
begin
IntA:=10;
IntB:=10;
SetDllDate; //更新DLL 文件的数据
end;
end;




procedure TForm1.FormDestroy(Sender: TObject);
begin
if DLLData <> nil then
UnmapViewOfFile(DLLData);
if FHandle <>0 then
CloseHandle(FHandle);
end;

//------------------------------------------------------------------------------



DLL 文件:

library MYDLL;

uses
Windows , Messages, {Dialogs,} SysUtils, Registry;

//windwos.pas中封装了HOOK的所有API函数。

{$R *.res}
type
TData = record
IntA, IntB :Integer;
end;
PData=^TData;

var
DLLData: PData;


//------------------------------------------------------------------------------

function SetDllDate : boolean; //外部调用
var
FHandle: LongWORD;
DLLData : PData;
begin
FHandle:=CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TData), '999999999999999');
if FHandle <> 0 then
DLLData:=MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if DLLData <> nil then
with DLLData^ do
begin
IntA:=3;
end;

Result:=True;


end;


//------------------------------------------------------------------------------
function myfunction : boolean;
begin
if 事件 then SetDllDate; //要经常调用
end;

//------------------------------------------------------------------------------

procedure MyDLLHandler(Reason: Integer);
begin
case Reason of
DLL_PROCESS_ATTACH : begin
SetDllDate;
end;

DLL_PROCESS_DETACH : begin
if DLLData <> nil then UnmapViewOfFile(DLLData);
end;
end;
end;


//------------------------------------------------------------------------------

exports
SetDllDate;

begin
DLLProc:=@MyDLLHandler;
MyDLLhandler(DLL_PROCESS_ATTACH);
//********************************

end.
 
后退
顶部