Systools的TStMemoryMappedFile中的CreateFileMapping用法

时间:2014-12-05 17:28:15

标签: delphi winapi shared-memory

SourceForge上的Systools库包含一个类,它基本上是内存映射文件视图的包装器。我在其构造函数中有一些关于其代码的特定行的查询(在此q的底部完整显示),即

  FMapObj := CreateFileMapping(THandle($FFFFFFFF), nil, RO3,
                             FMaxHi, FMaxLo, 'STMMFILE1');
如果构造函数的SharedData参数为True,则调用

。请注意,如果SharedData是 是的,FileName参数被忽略,名称' STMMFILE1'而是用来代替。

这些是我的疑问:

首先,没有使用名称' STMMFILE1',Systools OLH所指的是"内部名称",表示运行的所有TStMemoryMappedFile实例系统使用相同的内存映射文件,以便两对需要独立MMF的应用程序无法使用TStMemoryMappedFile?换句话说,如果我使用它在应用程序A和A之间共享数据。 B,我无法在同一台机器上使用它在应用程序之间共享数据C& D与A& A不同。 B的共享数据。

其次,http://msdn.microsoft.com/en-gb/library/windows/desktop/aa366537%28v=vs.85%29.aspx处的MSDN文档指出:

"The remainder of the name can contain any character except the backslash character (\)" 

这让我想知道CreateFileMapping如何与远程文件一起使用。这是打开远程文件句柄并将其作为第一个参数传递给CreateFileMapping的问题吗?如果是这样,那似乎与TStMemoryMappedFile.Create根本不兼容使用" THandle($ FFFFFFFF)",不会吗?

Systools TStMemoryMappedFile构造函数:

constructor TStMemoryMappedFile.Create(const FileName   : string;      {!!.02}
                                             MaxSize    : Cardinal;
                                             ReadOnly   : Boolean;
                                             SharedData : Boolean);
var
  RO1,
  RO2,
  RO3,
  RO4,
  FHi    : DWORD;
  SetSize: Boolean;
begin
  inherited Create;

  FMutex := CreateMutex(nil, False, nil);
  FSharedData := SharedData;
  if (FSharedData) then
    FHeaderSize := SizeOf(Word) + SizeOf(Cardinal)
  else
    FHeaderSize := 0;

  FReadOnly := ReadOnly;
  if (SharedData) then
    FReadOnly := False;
  if (FReadOnly) then begin
    RO1 := GENERIC_READ;
    RO2 := FILE_ATTRIBUTE_READONLY;
    RO3 := PAGE_READONLY;
    RO4 := FILE_MAP_READ;
    FMaxHi := 0;
    FMaxLo := 0;
  end else begin
    RO1 := GENERIC_READ or GENERIC_WRITE;
    RO2 := FILE_ATTRIBUTE_NORMAL;
    RO3 := PAGE_READWRITE;
    RO4 := FILE_MAP_WRITE;
    FMaxHi := 0;
    FMaxLo := MaxSize;
  end;

  if (not SharedData) then begin
    FHandle := CreateFile(PChar(FileName),
                          RO1,
                          FILE_SHARE_READ or FILE_SHARE_WRITE,
                          nil,
                          OPEN_ALWAYS,
                          RO2,
                          0);

    if (FHandle = INVALID_HANDLE_VALUE) then
      RaiseStError(EStMMFileError, stscCreateFileFailed);

    {reset FMaxLo if file is read/write and less < FileSize}
    {the result is that the file size cannot be changed but the contents can}
    {still be modified}
    FDataSize := GetFileSize(FHandle, @FHi);
    if (FDataSize <> $FFFFFFFF) then begin
      if (not ReadOnly) and (FDataSize > FMaxLo) then
        FMaxLo := FDataSize;
    end else begin
      CloseHandle(FHandle);
      RaiseStError(EStMMFileError, stscGetSizeFailed);
    end;
  end else
    FDataSize := 0;

  if (not SharedData) then begin
    FMapObj := CreateFileMapping(FHandle, nil, RO3, FMaxHi, FMaxLo, nil);
    SetSize := False;
  end else begin
    if (FMaxLo > (High(Cardinal) - FHeaderSize)) then
      FMaxLo := High(Cardinal) - FHeaderSize
    else
      FMaxLo := FMaxLo + FHeaderSize;
    FMapObj := CreateFileMapping(THandle($FFFFFFFF), nil, RO3,
                                 FMaxHi, FMaxLo, 'STMMFILE1');
    SetSize := (GetLastError = ERROR_ALREADY_EXISTS);
  end;

  if (FMapObj = INVALID_HANDLE_VALUE) then
    RaiseStError(EStMMFileError, stscFileMappingFailed);

  FBuffer := MapViewOfFile(FMapObj, RO4, 0, 0, FMaxLo);
  if (not Assigned(FBuffer)) then
    RaiseStError(EStMMFileError, stscCreateViewFailed);

  if (SharedData) then begin
    if (SetSize) then
      Move(PByteArray(FBuffer)[SizeOf(Word)-1], FDataSize, SizeOf(Cardinal))
    else begin
      Move(FHeaderSize, PByteArray(FBuffer)[0], SizeOf(Word));
      FDataSize := 0;
      Move(FDataSize, PByteArray(FBuffer)[SizeOf(Word)-1], SizeOf(Cardinal));
    end;
  end;
  {set position to beginning}
  FPos := FHeaderSize;

端;

1 个答案:

答案 0 :(得分:2)

行为会在SharedData上切换。您描述的代码是共享案例。由swap支持,并通过命名的文件映射共享。您询问是否所有进程都共享相同的映射。是的,那就是SharedData的全部想法。

当然,这种设计存在很大的缺陷。假设我创建了一对使用此组件共享的应用程序。你做同样的事情。在我的应用和您的应用出现在同一台计算机上之前,它一切正常。你可以想象下一步会发生什么。

您应该修改代码以允许类的使用者提供名称。

远程文件的问题与此无关,因为共享映射对象由交换文件支持。有关对象名称的文档链接与文件系统名称无关。这些是内核对象,位于内核对象命名空间下。对于远程文件,它们无法可靠地映射。