java如何传参数delphi ansistring,在Delphi XE4中使用类似于数组字节的AnsiString

Trying to move Delphi 2007 project to XE4. In Delphi 2007 I was using function that reads byte array from socket using Indy directly. I passed AnsiString casted to array of byte to var parameter of this function:

var data:AnsiString;

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

In Dlphi XE when I try to concatinate Data to another string I got access violation error.

Now I'm trying to simulate this problem in more simple code:

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;

Now I expect to see something like ==== in message box, but I got empty one. I supposed that XE AnsiString acts the same like Delphi 2007 Ansistring and you can use them like byte array in both cases.

What is the best way to solve filling AnsiString with bytes problem?

解决方案

It was never valid to cast an AnsiString to a byte array. That code was always broken and you got lucky (or unlucky depending on your point of view).

Managed string types, just like dynamic arrays, have an extra payload of information, metadata, that is stored just before the data payload. This metadata includes reference count, length etc. But the metadata for strings is not the same as for dynamic arrays. Simply put, a string is not a dynamic arrays. Your reinterpret cast is completely invalid. It was invalid in the old versions of Delphi, and it's just as invalid in the modern versions.

What's really going on under the hood is that the size of the metadata has changed with the introduction of Unicode support. The metadata for AnsiString has been expanded. It now contains, for instance, the code page of the string.

Now, when you call SetLength, a block of memory large enough for both metadata and payload is allocated. Suppose that memory is allocated at address P. The address that your variable (string or dynamic array) holds is set to P + metadata size. When you come to deallocate the object, the system moves to P - metadata size and calls FreeMem with that address. And here's the kicker. You use the size of a dynamic array metadata when you allocate, but the size of a string meta data when you deallocate. The result? BOOM! You just called FreeMem on an invalid address, one that has not been allocated to you.

The correct way to handle this is to give the Indy function what it wants. Namely a byte array. If you need to transfer to a string variable, copy the byte array's content into a new string. For instance using TEncoding.Default.GetString().

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值