DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: pixelcraft
今日帖子: 60
在线用户: 13
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/3 16:15:12
标题:
TmemoryStream释放出错 浏览:1616
加入我的收藏
楼主: Datasnap服务器上定义一个函数,返回类型是Tstream,如下

function TDSClient.GetDemo : TStream;
var
  stream: TMemoryStream;
  LQry: TFDQuery;
  Sa: TFDSchemaAdapter;
begin
  try
    Sa := TFDSchemaAdapter.Create(nil);
    LQry := TFDQuery.Create(nil);
    try
      with LQry do
      begin
        SchemaAdapter := Sa;
        Connection := dm.GetSYSConnection;
        SQL.Text := 'SELECT * FROM DEMO';
        Open;
      end;
      stream := TMemoryStream.Create;
      Sa.SaveToStream(stream, sfBinary);
      stream.Position := 0;
      Result := stream;
    except
      on e: Exception do
      begin
         raise ;
      end;
    end;
  finally
    FreeAndNil(LQry);
    FreeAndNil(Sa);
  end;

end;



在客户端这边 定义一个函数,调用服务器方法,如下

var
  DS: TDSClient;
  tbl: TFDMemTable;
  stream: TStream;
begin
    try
      tbl := TFDMemTable.Create(nil);
      stream := TMemoryStream.Create;
      DS := TDSClient.Create(con.DBXConnection);
      stream := DS.GetDemo //服务器上定义的函数
    finally
      FreeAndNil(tbl);
      FreeAndNil(DS);
      stream.free //这里出错,提示无效的指针操作
    end;
  end;

请教各位,这问题是什么原因
----------------------------------------------
-把学习当信仰
作者:
男 homejun (homejun) ★☆☆☆☆ -
盒子活跃会员
2018/12/3 16:49:35
1楼:  stream := DS.GetDemo
感觉这样不对吧?
----------------------------------------------
-delphi新资讯站 http://www.delphigear.cn
作者:
男 vga (vga) ★☆☆☆☆ -
盒子活跃会员
2018/12/3 17:22:16
2楼: stream := TMemoryStream.Create;          // 这里分配了一个

stream := DS.GetDemo //服务器上定义的函数       // 这里指向另外的地方
----------------------------------------------
-
作者:
男 looper (keyo) ★☆☆☆☆ -
盒子活跃会员
2018/12/3 17:48:23
3楼: 2楼已经指出了问题的关键,改成这样就可以了:

var
  DS: TDSClient;
  tbl: TFDMemTable;
  stream: TStream;
begin
    stream:= nil;
    try
      tbl := TFDMemTable.Create(nil);
      DS := TDSClient.Create(con.DBXConnection);
      stream := DS.GetDemo //服务器上定义的函数
    finally
      FreeAndNil(tbl);
      FreeAndNil(DS);
      if assigned(stream) then FreeAndNil(stream);
    end;
  end;
----------------------------------------------
虽千万人吾往矣!
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/3 21:30:06
4楼: 还是一样的提示 无效指针操作
----------------------------------------------
-把学习当信仰
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/12/3 22:22:25
5楼: 用json,别用TStream
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/3 23:37:03
6楼: 暂时不考虑用json
----------------------------------------------
-把学习当信仰
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2018/12/4 12:19:23
7楼: 估计是TDSClient自己释放了stream,你查看一下源代码。
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 博客挂了……
作者:
男 jackalan (nVicen) ★☆☆☆☆ -
盒子活跃会员
2018/12/4 14:24:33
8楼: 这样返回TSTREAM问题多多吧吗?

建议你改下返回方式:

function TDSClient.GetDemo(var sResult: TStream):Boolean;
begin
   Result := False;
   if not Assigend(sResult) then Exit;
   ......
   ......
   Result := True;
end;

调用的时候,客户端:
stream := TMemoryStream.Create;
if DS.GetDemo(stream ) then 
begin
   .......
   .......
end
else MsgBox...or Reture Msg;
if Assigned(stream) then FreeAndNil(stream);
----------------------------------------------
简单做人,认真做事。
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/12/4 14:33:14
9楼: 楼上正解。
不过我们一般用 ROSDK
就是这种类似的接口写法。
如果不是远程接口 var 都不用写。
但是 RO 的 var 流
输入的一个 a ,返回的肯定是 b
所以 a 和 b 都要销毁。

如果你不用 var 那么 a 的内容肯定不变。
也就没有返回内容。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 17:36:11
10楼: 但是我这样写的时候,客户端提示我 [dcc32 Error] DSClient.pas(209): E2010 Incompatible types: 'TMemoryStream' and 'TStream'
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 17:44:24
11楼: 我的环境是 delphi xe10.1 berlin  + win7
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 17:47:06
12楼: to 8楼,是的,有内存泄漏
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/12/4 17:48:13
13楼: 接 9 楼。
如果 流 不关心 输入。
那么 接口 应该用 out
RO SDK 调用的时候。
变量 不需要 初始化。
RO 接口会自动初始化。
只需要记得销毁就行。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 17:48:32
13楼: 大家可以试下,是不是datasnap不支持这个写法?
----------------------------------------------
-把学习当信仰
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2018/12/4 21:59:44
14楼:   DS := TDSClient.Create(con.DBXConnection);

TDSClient.Create应该还有一个重载的。后面带个boolean的参数。 

你改为
  DS := TDSClient.Create(con.DBXConnection, false); 试试
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2018/12/4 22:04:09
15楼: 另外也可以这样写
TXXX.GetPhoto(out Value: TStream): Boolean;
----------------------------------------------
学无止境
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 22:48:19
16楼: 很奇怪的问题:

1,服务端的函数如果加 out 或 var ,客户端调用提示 VAR and OUT arguments must match parameter type exactly

2. 如果不加out 或var ,客户调用提示 invalid binary storage format 

3.TDSClient.Create应该还有一个重载的。后面带个boolean的参数。 
 --是的,如果不加false,则会有泄漏,必须加 False并手动在finlly 里释放
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/4 23:15:38
17楼: 客户端获取到的流大小是0了
----------------------------------------------
-把学习当信仰
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2018/12/4 23:32:28
17楼: 1,服务端的函数如果加 out 或 var ,客户端调用提示 VAR and OUT arguments must match parameter type exactly
//----------
这个问题之前也遇到过,记不清是从XE的哪个版开如出这个错误的。之前是没有问题的,后来升级后就有问题了,代码没代,只是重新编译了一下。最早我好像是这样写的
TXXX.GetPhoto(out Value: TDBXStreamValue): boolean;

之所以会出现VAR and OUT arguments must match parameter type exactly这个问题,是TDBX内部有一些变化造成的。实际上也是有办法处理的,但由于担心后面会还会出其它的问题,最后来改成这样
TXXX.GetPhoto(out Value: TStream; DataSize: longword): boolean;

客户端大体上是copyfrom(v, DataSize)


关于第2个问题,后来一直没用过FD的数据集,都是转为JSON返回数据。
----------------------------------------------
学无止境
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2018/12/5 10:09:53
18楼: 谢谢楼上及各位,最终还是改成了最初的形式,客户端用copystream,手动释放Dsclient和stream
----------------------------------------------
-把学习当信仰
作者:
男 wanlgrm (么么) ▲▲▲▲▲ -
普通会员
2018/12/24 8:44:55
19楼: DataSnap 流传输必须用
function CopyStream(const AStream: TStream): TMemoryStream;
const
  LBufSize = $F000;
var
  LBuffer: TBytes;
  LReadLen: Integer;
begin
  Result := nil;
  if AStream = nil then
    Exit;
  Result := TMemoryStream.Create;
  try
    if AStream.Size = -1 then
    begin
      SetLength(LBuffer, LBufSize);
      repeat
        LReadLen := AStream.Read(LBuffer[0], LBufSize);
        if LReadLen > 0 then
          Result.WriteBuffer(LBuffer[0], LReadLen);
        if LReadLen < LBufSize then
          break;
      until LReadLen < LBufSize;
    end
    else
      Result.CopyFrom(AStream, 0);
    Result.Position := 0;
  except
    Result.Free;
  end;
end;
----------------------------------------------
-只会复制粘贴!
作者:
男 bjzhq ( oce) ★☆☆☆☆ -
盒子活跃会员
2018/12/24 9:04:48
20楼: to 16/17楼,DX10.2.3 已经解决了
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行70.3125毫秒 RSS