Entwickler-Ecke

Dateizugriff - Merkwürdiges Verhalten bei TRegistry.ReadBinaryData


Christian213 - Do 27.06.13 09:10
Titel: Merkwürdiges Verhalten bei TRegistry.ReadBinaryData
Hallo,

ich habe hier eine gefühlte Ewigkeit an einem merkwürdigen Problem im Zusammenhang mit "ReadBinaryData" rumgedoktort.
Laut Funktionsdefinition ist ReadBinaryData(const Name: string; var Buffer; BufSize: Integer): Integer;
So, also im Prinzip auf dem gewohnten Weg ein OpenKey einen Pfad öffnen, dann einfach einen vorher definierten Puffer nebst Puffergröße übergeben und als Returncode bekommen wir die Anzahl der tatsächlich gelesenen Zeichen, richtig?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
              bytesRead := regist.GetDataSize(Value);
              if bytesRead > 0 then
              begin
                SetLength(Buffer, bytesRead);
                regist.ReadBinaryData(Value, Buffer, bytesRead);

                (...)
 
              end;

Leider gibt es dann einen SIGSEGV in dem Moment, wo ReadBinaryData aufgerufen wird.

Nach langem Probieren habe ich nun folgende Lösung:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
              bytesRead := regist.GetDataSize(Value);
              if bytesRead > 0 then
              begin
                SetLength(Buffer, bytesRead);
                pBuffer := Pointer(Buffer);
                regist.ReadBinaryData(Value, pBuffer^, bytesRead);
                
                (...)

              end;

Die Frage die sich mir stellt ist: Wieso muss ich eine untypisierte Pointer-Variable definieren und diese dann de-referenziert übergeben?
Es funktioniert so zwar, ich wüsste nur gerne warum ich hier solche Verrenkungen machen muss.

Gruß,
Christian


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Do 27.06.2013 um 11:33


Gammatester - Do 27.06.13 09:45

user profile iconChristian213 hat folgendes geschrieben Zum zitierten Posting springen:
Die Frage die sich mir stellt ist: Wieso muss ich eine untypisierte Pointer-Variable definieren und diese dann de-referenziert übergeben?
Mußt Du das wirklich? Das ist mM die gleiche Situation wie zB bei system.move, also sollte doch eigentlich auch regist.ReadBinaryData(Value, Buffer[0], bytesRead); funktionieren.


Martok - Do 27.06.13 09:47

Hi!

Mein Vorschlag wäre erstmal:

Delphi-Quelltext
1:
2:
                SetLength(Buffer, bytesRead);
                regist.ReadBinaryData(Value, Buffer[0], bytesRead);

Hintergrund: untypisierte Parameter sind sowas ähnliches wie Pointer, die auf der andern Seite direkt dereferenziert werden. Du willst hier also die das erste Element angeben. Bei dynamischen Arrays liegt das aber grade nicht an der Stelle, wo die Variable ist: wie bei Strings ist "Buffer" erstmal nur ein Zeiger (mit angehängter Längenangabe) auf einen Speicherbereich, wo dann die echten Daten sind.

Bei einem Array mit fester Länge würde das übrigens funktionieren, da dort die Variable direkt den Speicherbereich bezeichnet und damit immer mit dem ersten Element identisch ist, ohne die weitere Ebene Verpointerung dazwischen.

Warum funktioniert dein Pointer?
Wie erwähnt ist Buffer ein Zeiger auf einen Speicherbereich. Pointer() (nicht Ptr() oder @) ist nur ein Typecast, du tust also nichts weiter, als dem Zeiger in Buffer folgen. Genau das also was passiert, wenn du auf das erste Element zugreifst.

An der Stelle mag ich FPC auch wieder, Delphi würde den Code vermutlich anstandslos ausführen, aber er würde nicht funktionieren. Durch den SegFault weißt du wenigstens direkt, dass du irgendwo wild im Speicher rumschreibst ;-)


... und da war der user profile iconGammatester schneller :zwinker:


Christian213 - Do 27.06.13 10:24

Hallo,

Danke für die Antworten.
Ihr habt natürlich Recht: Es geht auch mit Buffer[0].
Der Unterschied in der Adressierung war mir irgendwie gerade entfallen.
So macht das Ganze auch für mich wieder Sinn.

Gruß
Christian


jaenicke - Fr 28.06.13 21:53

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
An der Stelle mag ich FPC auch wieder, Delphi würde den Code vermutlich anstandslos ausführen, aber er würde nicht funktionieren. Durch den SegFault weißt du wenigstens direkt, dass du irgendwo wild im Speicher rumschreibst ;-)
Das hat nichts mit FPC oder Delphi zu tun, die Schutzverletzung kommt von Windows und das auch nur zufällig, weil der Speicher an der Stelle bekannt ist als nicht beschreibbar...
Setze vorher einfach mal den Pointer auf einen Bereich, der nicht ungültig ist und es kommt auch bei FPC keine Fehlermeldung.