I did an experiment to look into this and the result surprised me.
Let the DataSnapServer Wizard (under File | New | Other | Delphi Projects |
DataSnap Server) create a default server project and then make the following additions
type
TMyStringStream = class(TStringStream)
public
constructor Create(Value : String);
destructor Destroy; override;
end;
TServerMethods1 = class(TDSServerModule)
[...]
function TServerMethods1.GetStream(Value: String): TStream;
var
SS : TMyStringStream;
begin
SS := TMyStringStream.Create(Value);
SS.Position := 0;
Result := SS;
end;
constructor TMyStringStream.Create(Value: String);
begin
inherited Create;
WriteString(Value);
end;
destructor TMyStringStream.Destroy;
begin
Clear;
inherited;
end;
, compile, put a breakpoint on Clear in TMyStringStream.Destroy and run.
Then, create/run a minimal client which does something like this
procedure TDSClientForm.Button2Click(Sender: TObject);
var
SS : TStringStream;
S : TStream;
begin
SqlServerMethod2.Params[0].AsString := 'ABC123';
SqlServerMethod2.ExecuteMethod;
SS := TStringStream.Create;
try
S := SqlServerMethod2.Params[1].AsStream; //, 6{SqlServerMethod2.Params[1].Size});
S.Position := 0;
SS.CopyFrom(S, S.Size);
ShowMessage(SS.DataString);
finally
SS.Free;
end;
end;
If you then click Button2 in the client, you'll find that the server stops on
the breakpoint in TMyStringStream.Destroy. This is a result of FreeAndNil(FAllocatedReturn)
executing in the block
if not FServerSideCommand then
try
FreeAndNil(FAllocatedReturn)
except
Result := false
end;
in function TDSMethodValues.ClearReferenceParameters: boolean in DataSnap.DSReflect.
So it looks like a Stream which is allocated in your server method AND is assigned to
its Result will be freed (whether you like it or not), so that won't leak. But I think you should regard that as a narrow exception to the general rule that if you create a Delphi object via a local variable, you should dispose of it before the variable goes out of scope.