Toon posts:

[Delphi] Lezen uit geheugen aan de hand van een pointer

Pagina: 1
Acties:
  • 145 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Het volgende probleem houdt me bezig. Ik heb een stuk geheugen wat er zo uit ziet:
Afbeeldingslocatie: http://www.tweakers.net/ext/i.dsp?FotoAlbumID=1595&format=full&ext=.jpg

en ik heb een pointer (var MijnPointer: Pointer) naar dit stuk geheugen. Zo kom ik aan deze pointer:
code:
1
MijnPointer:=:=SysGetMem($1EF58)


waarna ik een bep. functie uit een DLL dat stuk geheugen laat vullen, totdat het er uit ziet zoals weergegeven in het plaatje.

Mijn bedoeling lijkt simpel. Ik wil een stuk van dat geheugen als string inlezen en weergeven.

Hoe doe ik dit?

Ik heb teveel zitten experimenteren om aan te geven wat ik allemaal al geprobeerd heb. Het enige wat ik ooit terugkrijg is rotzooi of lege strings.

//edit

mijn laatste poging ziet er zo uit:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
var MijnPointer: Pointer; 
      MijnStream: TMemoryStream;
      Buffer: PChar;
begin
  MijnPointer:=SysGetMem($1EF58);
  [ .. ] //knip stuk waar geheugen gevuld wordt
  Mijnstream.Write(MijnPointer^,SizeOf(MijnPointer^);
  Mijstream.Position:=16;
  MijnStream.Read(Buffer,20);
  ShowMessage(Buffer);
end;

[ Voor 43% gewijzigd door Verwijderd op 02-02-2003 06:44 ]


  • Aetje
  • Registratie: September 2001
  • Laatst online: 18-12-2025

Aetje

Troubleshooting met HAMERRR

Typecast Buffer eens als een stringtype...

Forget your fears...
...and want to know more...


  • Just_a_Gamer
  • Registratie: November 2001
  • Laatst online: 22:18
Je hebt in Delphi 6 ook een StringStream. Als je zorgt dat je MijnStream naar een StringStream "kopieert" Dan kan je het als string uit lezen met de property datastring.

  • Tomatoman
  • Registratie: November 2000
  • Nu online

Tomatoman

Fulltime prutser

Ten eerste moet je een keuze maken hoe je toegang tot de inhoud van het bestand krijgt. De meest voor de hand liggende keuzes zijn een memory stream en een memory mapped file. Een memory stream heb je zelf al gezien, dus die laat ik schieten.

Soortgelijke vragen komen heel vaak voor, dus daarom laat ik nu zien hoe je memory mapped files gebruikt. Het ziet er een beetje intimiderend uit, maar met copy-paste ben je direct klaar.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var
  FFileBase: Pointer;
  FFileMapping: THandle;
  FFileSize: Cardinal;

procedure LoadFile(const FileName: string);
var
  HFile: THandle;
begin
  { Create a file mapping object. }
  HFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
  if HFile = INVALID_HANDLE_VALUE then
    raise EFOpenError.CreateResFmt(@SFOpenError, [FileName]);
  try
    FFileSize := GetFileSize(HFile, nil);
    if FFileSize = $FFFFFFFF then
      RaiseLastOSError;          // in Delphi 2 t/m 5: RaiseLastWin32Error
    FFileMapping := CreateFileMapping(HFile, nil, PAGE_READONLY, 0, 0, nil);
    if FFileMapping = 0 then
      RaiseLastOSError;
  finally
    CloseHandle(HFile);
  end;
  FFileBase := MapViewOfFile(FFileMapping, FILE_MAP_READ, 0, 0, 0);
  if not Assigned(FFileBase) then
    FreeFile;
  end;
end;
Je hebt nu een memory mapped file. In essentie betekent dat dat het bestand is ingelezen in het geheugen. Windows zorgt voor het memory management, dat erg efficiënt is.

Ten tweede moet je bepalen waar de string begint. Dat is natuurlijk afhankelijk van het soort bestand dat je leest (in jouw geval een MP3?). Het levert je de offset op vanaf het begin van het bestand.

Ten derde moet je de string uitlezen. Om pointers op te tellen moet je ze typecasten als Cardinal.
Delphi:
1
2
3
4
5
6
7
8
var
  P: PChar;
  Naam: string;
begin
  Cardinal(P) := Cardinal(FFileBase) +
    Cardinal([offset van de string vanaf het begin van het bestand]);
  Naam := P;
end;
Ten vierde moet je de gealloceerde bronnen opruimen.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure FreeFile;
begin
  if FFileBase <> nil then
    if not UnMapViewOfFile(FFileBase) then
      RaiseLastOSError;
  FFileBase := nil;
  FFileSize := 0;

  if FFileMapping <> 0 then
    if not CloseHandle(FFileMapping) then
      RaiseLastOSError;
  FFileMapping := 0;
end;

[ Voor 9% gewijzigd door Tomatoman op 02-02-2003 13:29 . Reden: aanvullingen ]

Een goede grap mag vrienden kosten.


Verwijderd

Topicstarter
Tomatoman, perfect, bedankt!

Ik wist van het bestaan van memory mapped files af, heb het zelf in het verleden eens gebruikt om data uit te wisselen tussen een applicatie en een dll, maar was vergeten hoe het moest. Had er wel op gezocht bij Deja, maar kon de juiste term niet meer vinden.

Nu wel dus, ik ga het gelijk proberen. Zo intimiderend ziet die code er niet uit overigens ;)

//edit

iets te snel gezegd.. ik zie namelijk niet in hoe jouw post de oplossing voor mijn probleem is?

Waar laat ik bv. mijn pointer naar dat stuk geheugen? Ik heb dat stuk geheugen dus al, en kan die pointer niet meer veranderen.

Overigens zou dit dan ook moeten werken:

Delphi:
1
2
3
4
5
6
7
8
9
10
var MijnPointer: Pointer; 
      Buffer: PChar;
      Uitvoer: String;
begin
  MijnPointer:=SysGetMem($1EF58);
  [ .. ] //knip stuk waar geheugen gevuld wordt
  Cardinal(Buffer):=Cardinal(MijnPointer)+Cardinal(16);
  Uitvoer:=Buffer;
  ShowMessage(Buffer);
end;


maar helaas, dat geeft niet het gewenste resultaat.

Hoe geef ik overigens het einde van die string op? Ik zie wel hoe je met het optellen van de pointers de offset veranderd, maar er moet ook een eind aan die string zitten? ik wil niet 'alle chars vanaf positie 16', maar eigenlijk 'alle chars vanaf positie 16 t/m positie 192.

Het typecasten van de buffer naar string werkt ook niet, ik ga nu even kijken naar die StringStream...

//edit

ok, weer een poging mislukt:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
var
  FileBase: Pointer;
  MijnStream: TMemoryStream;
  MijnStringStream: TStringStream;
begin
  MijnStream:=TMemoryStream.Create;
  MijnStringStream:=TStringStream.Create('');
  FileBase:=SysGetMem($1EF58);
  dll_fn_refresh_device(FileBase,1000);
  Mijnstream.Write(FileBase^, SizeOf(FileBase^)-1);
  MijnStringStream.CopyFrom(MijnStream,208);
  ShowMessage(MijnStringStream.DataString);
end;


Geeft : 'Stream Read Error'..

//edit

hehe.. ik ben er eindelijk uit:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TForm1.Button1Click(Sender: TObject);
var Test: PChar;
    nLus: Integer;
    MijnString: String;
begin
  If not Allocated then
    begin
      FileBase:=SysGetMem($1EF58);
      Allocated:=True;
    end;
  dll_fn_refresh_device(FileBase,1000); // vullen geheugen
  for nLus:=0 to 16 do Inc(Cardinal(FileBase));
  Cardinal(Test):=Cardinal(FileBase);
  MijnString:=Copy(Test,1,100);
  ShowMessage(MijnString);
end;

[ Voor 91% gewijzigd door Verwijderd op 02-02-2003 15:31 ]