Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Record in Stream und zurück (https://www.delphipraxis.net/194838-record-stream-und-zurueck.html)

sko1 12. Jan 2018 11:17

Record in Stream und zurück
 
Hallo,

um einen (umfangreichen und Strings enthaltenden) Record mit WM_COPYDATA versenden zu können wollte ich diesen in einen TMemoryStream packen und diesen versenden.

Beim Auspacken aber funktioniert nur der erste String:

Verpacken:

Delphi-Quellcode:
  TMyRecord = packed record
    s1: string;
    s2: string;
  end;
...
rec : TMyRecord;
rec.s1:= 'langer String.....1';
rec.s2:= 'langer String.....2';

procedure RecordToStream(var ms: TMemorystream; rec: TMyRecord);
var
  c: Char;
  s: String;
  i: integer;
begin
  ms.Clear;
  i := length(rec.s1);
  ms.write(i, sizeof(i));
  for i := 1 to length(rec.s1) do
  begin
    c := rec.s1[i];
    ms.write(c, sizeof(c));
  end;
  i := length(rec.s2);
  ms.write(i, sizeof(i));
  for i := 1 to length(rec.s2) do
  begin
    c := rec.s2[i];
    ms.write(c, sizeof(c));
  end;
end;

Auspacken:

Delphi-Quellcode:
function StreamToRecord(ms: TMemorystream): TMyRecord;
var
  len: integer;
  sbuf: string;
begin
  ms.Position := 0;
  //Speichern zum Angucken
  ms.savetofile('c:\temp\stream.xxx');
  ms.Read(len, sizeof(len));
  sbuf := StringOfChar(#00, len);
  ms.Read(sbuf[1], len);
  result.s1 := sbuf;
  ms.Read(len, sizeof(len));
  sbuf := StringOfChar(#00, len);
  ms.Read(sbuf[1], len);
  result.s2 := sbuf;
end;
Hier ist die len des 2. Strings utopisch groß und s2 bekommt den Inhalt den auch s1 hat!
Der Stream wird korrekt übertragen, die gespeicherte Version sieht im Hexeditor korrekt aus, es muss also ein Fehler in StreamToRecord liegen, nur welcher?
ms.Position habe ich im Debugger ebenfalls kontrolliert, sieht normal und richtig aus...

Ciao
Stefan

Bernhard Geyer 12. Jan 2018 11:26

AW: Record in Stream und zurück
 
Strings kannst du über WM_COPYDATA nicht übertragen.
Du musst mit einem array of char arbeiten.

Zacherl 12. Jan 2018 11:47

AW: Record in Stream und zurück
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1390879)
Strings kannst du über WM_COPYDATA nicht übertragen.

Er packt ja alles in einen Stream. Das geht schon klar.

Zitat:

Zitat von sko1 (Beitrag 1390878)
Auspacken

Statt
Delphi-Quellcode:
StringOfChar
nimm hier lieber
Delphi-Quellcode:
SetLength
. Macht keinen wirklichen Unterschied, sollte aber performanter sein.

Dein wirkliches Problem ist allerdings, dass du
Delphi-Quellcode:
len
-Bytes ausliest und nicht
Delphi-Quellcode:
len * SizeOf(Char)
bzw.
Delphi-Quellcode:
len * SizeOf(sbuf[1])
.

Zitat:

Zitat von sko1 (Beitrag 1390878)
Verpacken

Hier brauchst du den String auch nicht Zeichen für Zeichen schreiben, sondern kannst analog zur "Auspacken" Routine direkt mit
Delphi-Quellcode:
Stream.Write(S[1], Length(S) * SizeOf(S[1]))
arbeiten.

sko1 12. Jan 2018 11:48

AW: Record in Stream und zurück
 
Das ist mir bekannt, deswegen wird ja alles in einen Stream verpackt!
Der kommt auch korrekt an, nur "rückinterpretieren" macht Fehler!

Ciao
Stefan

Fritzew 12. Jan 2018 11:53

AW: Record in Stream und zurück
 
nach Deinem

Delphi-Quellcode:
//Speichern zum Angucken
  ms.savetofile('c:\temp\stream.xxx'); //Stream Position ist jetzt am Ende des Files
// Was soll er hier einlesen?
  ms.Read(len, sizeof(len));
Read liefert Dir doch die Anzahl der gelesenen Bytes.
also sowas wie :
Delphi-Quellcode:
if ms.Read(len, sizeof(len)) = sizeof(len) then
begin
end
else
Error....

sko1 12. Jan 2018 11:55

AW: Record in Stream und zurück
 
Hallo Zacherl,

Zitat:

Dein wirkliches Problem ist allerdings, dass du len -Bytes ausliest und nicht len * SizeOf(Char) .
und da fällt es mir wie Schuppen aus den (nicht mehr vorhandenen) Haaren, klar, das war die Ursache!
Und schon funktioniert alles wie gewünscht und die 255 Byte ShortString-Beschränkung im Record ist mit dem Stream elegant ausgehebelt :-)

Da ich wirklich mit einem sehr langen String getestet habe (nicht wie im geposteten Code, sondern viiiel länger), habe ich nicht gesehen dass im ersten String auch schon nur die Hälfte stand, der Pointer daher mitten im ersten String und damit die utopische Längenangabe des zweiten Strings...

Vielen Dank!
Ciao
Stefan

sko1 12. Jan 2018 11:58

AW: Record in Stream und zurück
 
Hallo Fritzew,

die ms.Position ist vor dem SaveToFile = 0 und danach immer noch = 0!
Beim Speichern wird der Zeiger nicht ans Ende verschoben wie beim Lesen!

Die Zeile war ja nur zum Testen und kommt wieder raus...

Ciao
Stefan

Bernhard Geyer 12. Jan 2018 12:25

AW: Record in Stream und zurück
 
Zitat:

Zitat von Zacherl (Beitrag 1390882)
Zitat:

Zitat von Bernhard Geyer (Beitrag 1390879)
Strings kannst du über WM_COPYDATA nicht übertragen.

Er packt ja alles in einen Stream. Das geht schon klar.

Ups. Da habe ich wohl zu früh gemeint den Fehler zu sehen ... :wall:

Keldorn 13. Jan 2018 09:10

AW: Record in Stream und zurück
 
Hallo,

ein Blick auf TWriter und TReader lohnt sich auch, damit lässt es sich einfacher leben

Gruß Frank


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:36 Uhr.

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