在Delphi XE6中使用Data Snap传递TStream

时间:2016-05-24 22:02:46

标签: delphi datasnap

我需要在Delphi XE6中使用Data Snap传递一些东西(TStream& TClientdataSet)。让我们从TStream开始 - 也许我在这里学到的东西,我可以找出TClientDataSet

这是我的尝试,但它会引发错误:

  

远程错误:访问模块DSServer.exe中地址0040801C的违规行为

客户端演示(DSClient.exe)

//RunReportObj is the real object I will be passing to the server method

Procedure TForm8.Button1Click(Sender: TObject);
var
  RunReportObj: TRunReportObject;
  S: TStream;
  FS: TFileStream;
begin
  RunReportObj:= TRunReportObject.Create;
  RunReportObj.ID:= '10101';
  RunReportObj.ReportName:= 'Test';
  RunReportObj.ExportType:= 'PDF';
  S:= TStream.Create;
   try
    S:= ClientModule1.ServerMethods1Client.GetReport(RunReportObj);
    S.Seek(0,soFromBeginning);
    FS:= TFileStream.Create(RunReportObj.ReportName + '.' + RunReportObj.ExportType, fmOpenWrite);;
    try
      FS.CopyFrom(S, S.Size);
    finally
      FS.Free;
    end;
   finally
    S.Free;
   end;
end;

ClientClassesUnit1.pas

function TServerMethods1Client.GetReport(RunReportObj: TRunReportObject): TStream;
begin
  if FGetReportCommand = nil then
  begin
    FGetReportCommand := FDBXConnection.CreateCommand;
    FGetReportCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FGetReportCommand.Text := 'TServerMethods1.GetReport';
    FGetReportCommand.Prepare;
  end;
  if not Assigned(RunReportObj) then
    FGetReportCommand.Parameters[0].Value.SetNull
  else
  begin
    FMarshal := TDBXClientCommand(FGetReportCommand.Parameters[0].ConnectionHandler).GetJSONMarshaler;
    try
      FGetReportCommand.Parameters[0].Value.SetJSONValue(FMarshal.Marshal(RunReportObj), True);
      if FInstanceOwner then
        RunReportObj.Free
    finally
      FreeAndNil(FMarshal)
    end
    end;
  FGetReportCommand.ExecuteUpdate;
  Result := FGetReportCommand.Parameters[1].Value.GetStream(FInstanceOwner);
end;

服务器演示(DSServer.exe)

//not really doing anything with the RunReportObj yet,
// just trying to test whether or not I can pass a TStream back first

function TServerMethods1.GetReport(RunReportObj: TRunReportObject): TStream;
var
  Stream: TMemoryStream;
  Writer: TBinaryWriter;
  Bytes: TBytes;
begin
  result := TMemoryStream.Create;
  try
    Writer := TBinaryWriter.Create(result);
    try
      Writer.Write(TEncoding.UTF8.GetBytes('Hello World' + sLineBreak));
    finally
      Writer.Free;
    end;
  finally
    Stream.Free;
  end;
end;

我确定我做了一些愚蠢的事情:)

1 个答案:

答案 0 :(得分:4)

您必须小心谁负责释放使用DataSnap发送的对象。 TServerMethods1.GetReport()不应该释放Result,因为必须先将其发送给客户端。另一方面,只要TStream为真(默认情况下),客户端就不应该从TServerMethods1Client.GetReport()释放FInstanceOwner {。}}。

第一个条件是偶然实现的,尽管大卫指出,你正在释放未初始化的局部变量Stream。

目前无法对此进行实际测试,客户端的正确代码应如下所示:

Procedure TForm8.Button1Click(Sender: TObject);
var
  RunReportObj: TRunReportObject;
  S: TStream;
  FS: TFileStream;
begin
  RunReportObj:= TRunReportObject.Create;
  RunReportObj.ID:= '10101';
  RunReportObj.ReportName:= 'Test';
  RunReportObj.ExportType:= 'PDF';
  S:= ClientModule1.ServerMethods1Client.GetReport(RunReportObj);
  S.Seek(0,soFromBeginning);
  FS:= TFileStream.Create(RunReportObj.ReportName + '.' + RunReportObj.ExportType, fmOpenWrite);;
  try
    FS.CopyFrom(S, S.Size);
  finally
    FS.Free;
  end;
end;

对于服务器端:

function TServerMethods1.GetReport(RunReportObj: TRunReportObject): TStream;
var
  Writer: TBinaryWriter;
  Bytes: TBytes;
begin
  result := TMemoryStream.Create;
  Writer := TBinaryWriter.Create(result);
  try
    Writer.Write(TEncoding.UTF8.GetBytes('Hello World' + sLineBreak));
  finally
    Writer.Free;
  end;
end;