在Delphi XE4中使用类似AnsiString的数组字节

时间:2013-12-16 12:57:03

标签: string delphi delphi-xe indy10

尝试将Delphi 2007项目移至XE4。在Delphi 2007我使用的函数直接使用Indy从套接字读取字节数组。我将AnsiString转换为此函数的var参数的字节数组:

var data:AnsiString;
AContext.Connection.IOHandler.ReadBytes(TIDBytes(Data), PacketLength-PacketLengthDelta-1, False);

Dlphi XE中,当我尝试将Data连接到另一个字符串时,我遇到access violation错误。

现在我试图用更简单的代码模拟这个问题:

TIdBytes = array of Byte;

procedure fill(var b: TIDBytes);
begin
setlength(b,5);
b[0]:=61;
b[1]:=61;
b[2]:=61;
b[3]:=61;
b[4]:=61;

//original function used move function
end;



procedure TMainForm.FormCreate(Sender: TObject);
var s: ansistring ;
begin
fill( TIDBytes(s) );
Showmessage(s);
end;

现在我希望在消息框中看到====之类的东西,但我得到了空的。我认为XE AnsiString的作用与Delphi 2007 Ansistring相同,你可以在两种情况下都像字节数组一样使用它们。

用字节问题解决填充AnsiString的最佳方法是什么?

2 个答案:

答案 0 :(得分:5)

AnsiString强制转换为字节数组永远无效。那段代码总是坏了,你很幸运(或者根据你的观点不幸)。

托管字符串类型,就像动态数组一样,具有额外的信息有效负载,元数据,存储在数据有效负载之前。此元数据包括引用计数,长度等。但字符串的元数据与动态数组的元数据不同。简单地说,字符串不是动态数组。您的重新解释演员表完全无效。它在旧版本的Delphi中无效,在现代版本中它也同样无效。

真正发生的事情是,随着Unicode支持的引入,元数据的大小已经改变。 AnsiString的元数据已经扩展。例如,它现在包含字符串的代码页。

现在,当您调用SetLength时,会分配足够大的元数据和有效负载的内存块。假设在地址P处分配了内存。您的变量(字符串或动态数组)保存的地址设置为P +元数据大小。当您解除分配对象时,系统将移至P - 元数据大小并使用该地址调用FreeMem。这是踢球者。分配时使用动态数组元数据的大小,但是在解除分配时使用字符串元数据的大小。结果?繁荣!您刚刚在无效地址上调用FreeMem,该地址尚未分配给您。

处理这个问题的正确方法是给Indy函数提供它想要的东西。即一个字节数组。如果需要传输到字符串变量,请将字节数组的内容复制到新字符串中。例如,使用TEncoding.Default.GetString()

答案 1 :(得分:1)

使用您的填充程序和您的TIDBytes定义:

procedure Test;
var
  s: ansistring;
  b: TIDBytes;
begin
  fill(b);
  s := StringOf(TArray<byte>(b));
  ShowMessage(s);
end;

PS:@David答案是正确的,但你可以使用directy字节数组,然后使用StringOf来获取字符串/ ansistring