String to TStream
Asked Answered
N

4

8

I'm attempting to convert a string to a TStream. My code below gives me an "Abstract Error" message on the CopyFrom line. I'm against a brick wall here, any ideas on how to solve this?

procedure StringToStream(const AString: string; out AStream: TStream);
var
  SS: TStringStream;
begin
  SS := TStringStream.Create(AString);
  try
    SS.Position := 0;
    AStream.CopyFrom(SS, SS.Size);  //This is where the "Abstract Error" gets thrown
  finally
    SS.Free;
  end;
end;
Negotiant answered 4/7, 2009 at 16:50 Comment(0)
L
8

AStream is declared as OUT parameter, which means it isn't assigned at the beginning of the procedure and the procedure is responsible to assign a proper value to it.

If I interpret your code correct, you should omit the OUT and make sure AStream is instantiated properly when you call the routine.

Some more code showing the call of StringToStream may give some more clues.

Lightweight answered 4/7, 2009 at 18:36 Comment(3)
Well, clearly AStream is assigned if he's getting an abstract error when he calls a method on it. It's probably instantiated as a TStream instead instead of some descendant class.Kwarteng
You are right. And as the actual declaration of the value given for AStream has to be exactly TStream (otherwise the compiler would complain), there is a high probability that it actually is an instance of the abstract TStream instead of some inherited class. But besides that it is still not a wise decision to make it an out parameter.Lightweight
Thanks to all who offered up help. I was calling it with just a TStream, which I now realize doesn't make much sense. I changed to calling the procedure with a TMemoryStream and altered the procedure to (removing the out): procedure StringToStream(const AString: string; AStream: TMemoryStream); var SS: TStringStream; begin SS := TStringStream.Create(AString); try SS.Position := 0; AStream.CopyFrom(SS, SS.Size); finally SS.Free; end; end; This seems to have solved the issue. Again, many thanks!Negotiant
J
10

The following procedure should do excactly what your looking for. Please note that your usage of AStream is responsible for freeing the instance that is created in this procedure. It is perfectly fine to return the parent class (in this case tStream) rather than the specific descendant.

procedure StringToStream(const AString: string; out AStream: TStream);
begin
  AStream := TStringStream.Create(AString);
end;

You can also code this as a function:

Function StringToStream(const AString: string): TStream;
begin
  Result := TStringStream.Create(AString);
end;
Jed answered 6/7, 2009 at 16:18 Comment(0)
L
8

AStream is declared as OUT parameter, which means it isn't assigned at the beginning of the procedure and the procedure is responsible to assign a proper value to it.

If I interpret your code correct, you should omit the OUT and make sure AStream is instantiated properly when you call the routine.

Some more code showing the call of StringToStream may give some more clues.

Lightweight answered 4/7, 2009 at 18:36 Comment(3)
Well, clearly AStream is assigned if he's getting an abstract error when he calls a method on it. It's probably instantiated as a TStream instead instead of some descendant class.Kwarteng
You are right. And as the actual declaration of the value given for AStream has to be exactly TStream (otherwise the compiler would complain), there is a high probability that it actually is an instance of the abstract TStream instead of some inherited class. But besides that it is still not a wise decision to make it an out parameter.Lightweight
Thanks to all who offered up help. I was calling it with just a TStream, which I now realize doesn't make much sense. I changed to calling the procedure with a TMemoryStream and altered the procedure to (removing the out): procedure StringToStream(const AString: string; AStream: TMemoryStream); var SS: TStringStream; begin SS := TStringStream.Create(AString); try SS.Position := 0; AStream.CopyFrom(SS, SS.Size); finally SS.Free; end; end; This seems to have solved the issue. Again, many thanks!Negotiant
A
6

CopyFrom calls ReadBuffer, which calls Read, and Read is declared abstract. What sort of stream are you passing to AStream? If it doesn't implement Read, you'll get an abstract error there. (And the compiler should give you a warning when you instantiate it.)

Androclinium answered 4/7, 2009 at 17:14 Comment(2)
Precisely. The AStream being declared as a TStream is calling the Read method of the base class. He would have to specify a class(TStream) that implements the read method.Admiral
No, Yozey, being declared as a TStream isn't what causes the abstract function to be called. The function is virtual. The abstract function is called because an actual TStream object has been passed in (or some other descendant that hasn't overridden that function yet.Kwarteng
F
4

Declaring AStream as out looks wrong to me. Try removing the out.

If that doesn't help, here is the function I use:

procedure StringToStream(Stream: TStream;const S: String);
begin
Stream.Write(Pointer(S)^, length(S));
end;
Fontes answered 4/7, 2009 at 18:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.