Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi MemoryMappedFiles - Geht ja gar nicht (https://www.delphipraxis.net/107751-memorymappedfiles-geht-ja-gar-nicht.html)

Zacherl 1. Feb 2008 16:04


MemoryMappedFiles - Geht ja gar nicht
 
Hey,

so langsam zweifele ich an meinen Fähigkeiten. Folgende Unit hatte ich mir gebastelt:

Delphi-Quellcode:
procedure WriteToMMF(Filename: PChar; Data: Pointer; Len: Int64);
var
  hFile: Cardinal;
  Mem: Pointer;
begin
  hFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, Len, Filename);
  if hFile <> 0 then
  begin
    try
      Mem := MapViewOfFile(hFile, FILE_MAP_WRITE, 0, 0, 0);
      if Assigned(Mem) then
      begin
        try
          CopyMemory(Mem, Data, Len);
        finally
          //UnmapViewOfFile(Mem);
        end;
      end;
    finally
      //CloseHandle(hFile);
    end;
  end;
end;

function ReadFromMMF(Filename: PChar; Len: Int64): Pointer;
var
  hFile: Cardinal;
begin
  hFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READONLY, 0, Len, Filename);
  if hFile <> 0 then
  begin
    try
      Result := MapViewOfFile(hFile, FILE_MAP_READ, 0, 0, 0);
    finally
      //CloseHandle(hFile);
    end;
  end
    else
  begin
    Result := nil;
  end;
end;

procedure WriteMMFString(Filename: PChar; Value: String);
var
  Buf: Pointer;
  Len: Int64;
  hMem: Cardinal;
begin
  Len := Length(Value);
  hMem := GlobalAlloc(GPTR, Len + SizeOf(Int64));
  Buf := GlobalLock(hMem);
  try
    CopyMemory(Buf, @Len, SizeOf(Int64));
    CopyMemory(Pointer(Cardinal(Buf) + SizeOf(Int64)), @Value[1], Len);
    WriteToMMF(Filename, Buf, Len + SizeOf(Int64));
  finally
    GlobalUnlock(hMem);
    GlobalFree(hMem);
  end;
end;

function ReadMMFString(Filename: PChar; var Len: Int64): Pointer;
var
  Data: Pointer;
begin
  Result := nil;
  Data := ReadFromMMF(Filename, SizeOf(Int64));
  try
    if Assigned(Data) then
    begin
      Len := Cardinal(Data^);
      Data := ReadFromMMF(Filename, SizeOf(Int64) + Len);
      try
        if Assigned(Data) then
        begin
          Result := GlobalLock(GlobalAlloc(GPTR, Len));
          CopyMemory(Result, Pointer(Cardinal(Data) + SizeOf(Int64)), Len);
        end;
      finally
        //UnmapViewOfFile(Data);
      end;
    end;
  finally
    //UnmapViewOfFile(Data);
  end;
end;
Anwendung [1] schreibt nun mittels WriteMMFString mehrere String und mittels WriteToMMF einen Cardinal. Anwendung [2] ließt nun mittels ReadMMFString die Strings wieder aus und mittels ReadFromMMF den Cardinal. Das Problem ist folgendes: Mindestens einer der Werte wird nicht ausgelesen. Es wird allerhöchstens 00 zurückgegeben.
Irgendwie scheine ich das Prinzip aber auch noch nicht ganz verstanden zu haben. Die auskommentierten Befehle darf ich nicht aufrufen, weil sonst schonmal direkt überhauptnichts ankommt.

Das Problem ist auch, dass Anwendung [2] normalerweise permanent läuft. Gebe ich also die Mappings nicht wieder frei gibt es irgendwann Durcheinander bei den Daten die gelesen werden. Auch schreibt Anwendung [1] einen der Strings in einem festen Interval neu, da sich dieser auch laufend ändert.

Hat jemand eine Idee wie man das Problem lösen kann?

Gruß

Apollonius 1. Feb 2008 16:08

Re: MemoryMappedFiles - Geht ja gar nicht
 
Zitat:

Die auskommentierten Befehle darf ich nicht aufrufen, weil sonst schonmal direkt überhauptnichts ankommt.
Zumindest das lässt sich erklären: Wenn das letzte Handle auf eine MMF geschlossen wird, zerstört Windows das Objekt. Also wird beim erneuten Öffnen eine neue MMF angelegt und die alten Daten sind futsch.

Zacherl 1. Feb 2008 17:13

Re: MemoryMappedFiles - Geht ja gar nicht
 
Und die Sache, dass nicht alle MMFs ausgelesen werden können? Bzw wann muss ich dann UnmapViewOfFile verwenden? Nach dem Lesen?

himitsu 9. Feb 2008 19:21

Re: MemoryMappedFiles - Geht ja gar nicht
 
UnmapViewOfFile rufst du auf, sobald das Programm (wo gemppt wurde keinen Zugriff mehr braucht ... notfalls kann man ja später nochmals neu mappen.

CloseHandle sobald der Speicher nicht mehr benötigt wird.

Solange mindestens eine Anwendung noch zugriff hat, bleibt der Speicher erhalten.

Also erst wenn alle Anwendungen den Zugriff per CloseHandle beendet haben (wenn die Anwendung selbst beendet wird, dann schleißt Windows automatisch das zugehörige Handle), dann wird die MMF gelöscht.

Kurzfassung ohne Fehlerbehandlung:
Delphi-Quellcode:
function CreateMMF(Filename: PChar; Daten...): THandle;
var
  Mem: Pointer;
begin
  Result := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, Len, Filename);
  Mem := MapViewOfFile(hFile, FILE_MAP_WRITE, 0, 0, 0);
  // hier Daten in MMF kopieren
  UnmapViewOfFile(Mem);
end;

procedure CloseMMF(H: THandle);
begin
  CloseHandle(H);
end;

procedure ReadMMF(Filename: PChar; Daten...);
var
  H: THandle;
  Mem: Pointer;
begin
  Result := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, Len, Filename);
  Mem := MapViewOfFile(hFile, FILE_MAP_READ, 0, 0, 0);
  // hier Daten der MMF auslesen
  UnmapViewOfFile(Mem);
  CloseHandle(H);
end;
Delphi-Quellcode:
H := CreateMMF(Name, Daten);
// dem anderem Programm mitteilen, das es auszulesen hat und warten bis dieses fertig ist
CloseMMF(H);

Es geht aber noch schlimmer ... ich arbeite derzeit mit unnamedMMFs und da darf/muß ich jedesmal die Handles umwandeln, damit das andere Programm die MMF überhaupt findet -.-''


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz