使用MemoryStream.CopyFrom时访问冲突

时间:2012-11-08 16:03:51

标签: delphi stream access-violation

这会很长!

我正在制作一个用于管理丢弃的UDP数据包的重传方案,用于我正在进行的LAN仿真协议。

数据包存储

TDataBuffer = record

  PacketID : WORD;
  Packet   : TMemoryStream;

end;
PDataBuffer = ^TDataBuffer;

相关DataModule类成员

fRxDataPacketList  : TThreadList20;
fTxDataPacketList  : TThreadList20;

procedure CreateDataBuffer
          (PacketID : WORD; Packet : TMemoryStream;
           var DataBuffer : PDataBuffer);

procedure DestroyDataBuffer
          (var DataBuffer : PDataBuffer);

procedure AddPacketToPacketList
          (PacketID : WORD; Packet : TMemoryStream;
           RecievedPacket : Boolean);

function  GetPacketFromTxDataPacketList
          (PacketID : WORD; var Packet : TMemoryStream): Boolean;

TThreadList20:这是我自己的线程友好,加密和压缩支持TList的包装类。

还有另一个处理Rx方面的程序,这与我的问题无关,所以我正在跳过它。

创作

procedure TDataModuleClient.CreateDataBuffer
          (PacketID : WORD; Packet : TMemoryStream; 
           var DataBuffer : PDataBuffer);

begin

  New (DataBuffer);
  DataBuffer.PacketID := PacketID;
  DataBuffer.Packet   := TMemoryStream.Create;

  if Assigned (Packet) then 
  begin

    DataBuffer.Packet.CopyFrom (Packet,Packet.Size); // NO AV HERE
    DataBuffer.Packet.Position := 0;

  end;

end;

销毁

procedure TDataModuleClient.DestroyDataBuffer
          (var DataBuffer : PDataBuffer);
begin

  DataBuffer.Packet.Free;
  Dispose (DataBuffer);

end;

添加到列表

procedure TDataModuleClient.AddPacketToDataPacketList
          (PacketID : WORD; Packet : TMemoryStream; RecievedPacket : Boolean);
var
  DataBuffer : PDataBuffer;

begin

  CreateDataBuffer (PacketID,Packet,DataBuffer);

  if RecievedPacket then
    fRxDataPacketList.Add (TObject (DataBuffer))

  else
  begin

    fTxDataPacketList.Lock;

    try

      fTxDataPacketList.Add (TObject (DataBuffer));

      if fRxDataPacketList.Count = 21 then
      begin

        DataBuffer := PDataBuffer (fTxDataPacketList [0]);

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (0);

      end;

    finally fTxDataPacketList.Unlock;
    end;

  end;

end;

从列表中提取

function  TDataModuleClient.GetPacketFromTxDataPacketList
          (PacketID : WORD; var Packet : TMemoryStream): Boolean;
var
  DataBuffer : PDataBuffer;
  I          : Integer;

begin

  Result := False;
  fTxDataPacketList.Lock;

  try

    for I := fTxDataPacketList.Count - 1 downto 0 do
    begin

      DataBuffer := PDataBuffer (fTxDataPacketList [I]);

      if DataBuffer.PacketID < PacketID then
      begin

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (I);

      end
      else if DataBuffer.PacketID = PacketID then
      begin

        Result := True;

        Packet := TMemoryStream.Create;

        Packet.CopyFrom
        (DataBuffer.Packet,DataBuffer.Packet.Size); // AV HERE
        Packet.Position := 0;

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (I);

        break;

      end;

    end;

  finally fTxDataPacketList.Unlock;
  end;

end;

数据包:输出变量。

请帮助我,我知道由于代码量的原因,它可能是一个很难推断的东西。

1 个答案:

答案 0 :(得分:2)

基于这个有限的代码,我正在做一些猜测:

1)在调用Packet之前,传递给GetPacketFromTxDataPacketList()的输入CopyFrom()可能尚未实际实例化。这将解释AV。

2)因为Packet参数被声明为var,这告诉我它是GetPacketFromTxDataPacketList()应该创建并返回的输出参数,而不是调用者创建TMemoryStream并将其传递到GetPacketFromTxDataPacketList()以填充数据。这也会成为#1,因为GetPacketFromTxDataPacketList()没有创建新的TMemoryStream对象,它假设事先已经创建了对象。