Indy Changed from Indy10

http://stackoverflow.com/questions/16339656/delphi-xe4-indy-compatibility-issue-between-tbytes-and-tidbytes

http://stackoverflow.com/questions/19402374/delphi-xe3-indy-compatibility-issue-between-tbytes-and-tidbytes

http://stackoverflow.com/questions/18849053/how-should-i-adapt-my-code-for-compatibility-between-tbytes-and-tidbytes

Today I try to compile my XE3 project in XE4. First problem that I face is with Indy‘s FTCPClient.Socket.ReadBytes() method.

Before it was accepting TBytes type, now it insists on TidBytes.

Definitions: TIdBytes = array of Byte; TBytes, Im not sure I guess it is generics something like TArray which is array of Byte.

Question number 1: Why does compiler complain by saying that‘[dcc32 Error] HistoricalStockData.pas(298): E2033 Types of actual and formal var parameters must be identical‘. As I see they are already identical.

Question number 2: Should I modify my source code with the each new delphi version?

Thanks.

Answers:

The reason TIdBytes was a simple alias for TBytes in earlier Indy 10 releases was primarily for compatibility with SysUtils.TEncoding, which uses TBytes. Indy‘s TIdTextEncoding type used to be a simple alias for SysUtils.TEncoding in D2009+, so TIdBytes needed to be a simple alias for TBytes to match.

However, TBytes caused quite a bit of trouble for Indy in XE3, mainly because of RTTI problems with Generics (TBytes is a simple alias for TArray<Byte> in recent Delphi releases). So, Indy 10.6 re-designed TIdTextEncoding to no longer rely on SysUtils.TEncoding at all (there were other reasons as well for doing so), which then allowed TIdBytes to change into its own array type in order to avoid the XE3 issues moving forward.

On the other hand, you were passing a TBytes where a TIdBytes was expected, so that is bad programming on your part for not following Indy‘s defined interface in the first place. All of Indy 10‘s byte-based operations, including ReadBytes(), have always operated on TIdBytes only. The fact that TIdBytes silently mapped to TBytes was an implementation detail that you should not have relied on in your code. Indy 10 expects TIdBytes, so use TIdBytes, then you would not have compiler errors about incompatible types.

share|improve this answer

edited May 2 ‘13 at 17:18

answered May 2 ‘13 at 16:24

Remy Lebeau

149k882162

1

Libraries that invent their own types instead of using equivalent RTL types just leads to ghettoisation. How can we write code that uses Indy and its byte array and interacts with another library using its byte array? – David Heffernan May 4 ‘13 at 0:31

First tell Embarcadero to stop breaking their own products when they make RTL changes. TBytes used to be a simple dynamic array (like TIdBytes is now). It worked great with RTTI, Object Inspector, compiler, etc. Then they switched TBytes to TArray<Byte> and broke all of that (bad Generics RTTI, bad C++ codegen, etc). Also remember that Indy supports multiple languages, and TArray<T> works differently in C++ than in Delphi. So there were multiple reasons for making TIdBytes go back to a simple dynamic array. I didn‘t make the change lightly, and even Embarcadero recommended I do it at the time. –  Remy Lebeau May 4 ‘13 at 3:13

OK, I‘m sure you had good reason to change. It feels all wrong to me that in 2013 there‘s still debate over how to handle byte arrays. The "right" solution, assuming everything could be made to work, would be for all code to use TArray<T> directly and so enjoy the special type compatibility rules for generic types. So in an ideal world there would be no TBytes, no TIdBytes, and libraries could happily co-exist and interact smoothly. –  David Heffernan May 4 ‘13 at 14:52

The following two declarations are not the same, even though they appear to be. They‘re not assignment compatible, even though they‘re both based on array of string.

type

TStringArrayOne = array of string;

TStringArrayTwo = array of string;

var

AVar1, AVar2: TStringArrayOne;

AVar3, AVar4: TStringArrayTwo;

begin

AVar1 := TStringArrayOne.Create(‘a‘, ‘b‘, ‘c‘);   // Compiles

AVar2 := TStringArrayTwo.Create(‘a‘, ‘b‘, ‘c‘);   // Won‘t compile

AVar3 := TStringArrayTwo.Create(‘a‘, ‘b‘, ‘c‘);   // Compiles

AVar4 := TStringArrayOne.Create(‘a‘, ‘b‘, ‘c‘);   // Won‘t compile

end;

So TBytes and TIdBytes are not the same type, even if they‘re both defined as being array of Byte.

With regard to your question 2: It‘s a common problem with some third-party code. Indy in particular is known for making changes that breaks backward compatibility because they decide to reorganize or rewrite things between versions. Indy 10 was a major change from Indy 9, IIRC, and pretty much required a rewrite of most code that used it if you updated to the later version of Indy (even without updating Delphi at the same time). If you don‘t want to deal with those changes, you might want to look at using a more stable IP communications package. There are several available that are also free, open source packages.

In Indy 10.5.9 the type TIdBytes was defined differently depending on the presence of an existing TBytes type - see unit IdGlobal:

{$IFDEF HAS_TBytes}

TIdBytes = TBytes;

{$ELSE}

TIdBytes = array of Byte;

{$ENDIF}

In Indy 10.6 (included in XE4), the declaration changed to unconditionally

TIdBytes = array of Byte;

which means that starting with Indy 10.6, IdGlobal.TIdBytes is different from SysUtils.TBytes.

The second question is hard to answer, it is more a question of your priorities - other libraries are not immune against changes either, for example to improve performance or type-safety. Also changes in the Delphi language can always affect existing code.

Question2:

3

down vote

favorite

I am having the same problem as mentioned in "Delphi XE4 Indy compatibility issue between TBytes and TidBytes ", i.e. compatibility issues between TBytes(Delphi RTL) and TIdBytes(Indy) datatypes when compiling with the Delphi XE4. The source of my problem is that the code is not exactly according to Indy‘s interface and some of functions use TBytes, instead of TIdBytes, when calling native Indy IO procedures.

So I was wondering what will the best fix be?

As I see it there are two approaches:

1.Refactor all functions in the project to use TIdBytes rather than TBytes.

2.Implement a TBytesToTidBytes conversion procedure (converts the TBytes to TIdBytes) and call that procedure prior to making the mentioned native Indy calls.

Which of the approaches is better/best? Do you have any other ideas on how I can do that?

FYI: The project I am trying to configure with the XE4 is available online on sourceforge : http://sourceforge.net/projects/indy10clieservr/?source=directory

The suggested conversion procedure should be something like:

procedure TBytesToTIdBytes(const Input:TBytes, var Output: TIdBytes)

var

i,L : Integer;

allocate : Boolean;

begin

L := Length(Input);

if(Length(Output) <> L) then

begin

SetLength(Output,L);

end;

if(L > 0) then

move(Pointer(Input)^,Pointer(Output)^,L);

end;

Answer:

TBytes and TIdBytes are both implemented as dynamic arrays, they are simply declared differently. The "politically correct" solution is to make a copy of the bytes. But that can waste memory for large arrays. A simpler solution is to use a typecast so you can utilize the array‘s internal reference count, eg:

type

PIdBytes = ^TIdBytes;

var

B1: TBytes;

B2: TIdBytes;

begin

B1 := ...;

B2 := PIdBytes(@B1)^;

end;

Or simply:

var

B1: TBytes;

B2: TIdBytes;

begin

B1 := ...;

B2 := TIdBytes(B1);

end;

Both types are not the same at implementation level, in newer Delphi versions (TBytes is a simple alias for TArray<Byte> in recent Delphi releases).

So I guess you can use such a procedure:

procedure TBytesToTIdBytes(const Input: TBytes; var Output: TIdBytes);

var L: integer;

begin

L := Length(Input);

SetLength(Output,L);

move(Input[0],Output[0],L);

end;

Here move() is faster than a loop.

时间: 2024-12-28 11:28:46

Indy Changed from Indy10的相关文章

Indy10.2.5的危险做法

为了排查一个Bug今天无意看了看Indy源码,结果吓了一跳.TIdIOHandler.ReadLongWord函数用于读取通讯数据并转换成LongWord类型返回,它做用了一种危险的做法可能会导致数据传输不正确. 函数源码如下: function TIdIOHandler.ReadLongWord(AConvert: Boolean): LongWord;var  LBytes: TIdBytes;begin  ReadBytes(LBytes, SizeOf(LBytes), False); 

Delphi组件indy 10中IdTCPServer修正及SSL使用心得

indy 10终于随着Delphi2005发布了,不过indy套件在我的印象中总是复杂并且BUG不断,说实话,不是看在他一整套组件的面子上,我还是喜欢VCL原生的Socket组件,简洁,清晰.Indy9发展到了indy10几乎完全不兼容,可叹啊.言归正传.在使用IdTCPServer组件的时候发现了他的漏洞,他的OnConnec,OnExecute,OnDisconnect等事件是在其他线程中执行的,通常情况下这没有问题,但是在特殊的情况下会造成问题,如果其他部分的程序写得有问题就会出现漏洞.

Delphi中Indy 10的安装和老版本的卸载

Delphi中Indy 10的安装和老版本的卸载 http://www.cnblogs.com/railgunman/archive/2010/08/31/1814112.html Indy 10的安装和老版本的卸载 Indy 10下载地址: http://www.indyproject.org/downloads/10/indy10.0.52_source.zip Indy 10 安装步骤 1.解压压缩包. 2.打开\System\IndySystem70.dpk,点Compile. 3.打开

Indy的TCPServer到底能支持多少个连接

最近一个项目,最开始使用IdTcpServer,在大压力测试的时候,只连接了800个多一点的客户端(每个客户端连接上之后每秒钟发送一个几十字节的报文,服务器应答).但是持续的时间不会超过10分钟,服务器就会挂掉(经常是服务器突然关闭消失,任何提示都没有).后来优化了互斥量之后,可以连接到1000多个客户端.但是服务器消失的问题依然存在.    今天再一台双CPU,4G内存的服务器上试验了下,居然最也只能连接到2000多个客户端.然后换了Indy10.1.5服务器只做简单的连接和应答,客户端连接之

indy idhttpserver有关下载的两个问题

http://aawwmate.blog.163.com/blog/static/77528256201092733950315/ indy idhttpserver有关下载的两个问题 2010-10-27 15:39:50|  分类: DELPHI|举报|字号 订阅 下载LOFTER我的照片书  | 1.IdHttpServer返回网页浏览器没直接显示,而是弹出下载对话框的解决方法 最近用Indy10的TIdHttpServer写一个简单的http服务器,原来按网上一个indy9的方法返回服务

Indy10 Tcp接收数据问题

在做Delphi开发时,使用Indy组件来做网络通讯是一种比较快捷的方式.今天要说一下indy10中tcp接收数据的问题. 我们在测试时经常使用Wrinteln来发送数据,用Readln来接收数据.用这个两个函数来测试Server端和Client端的通讯 是否正常.但在实际使用中我们很多时候发送的数据包都是比较复杂的,并不会带有回车键.也有可能用来接收XML报文, 在报文中是可能包含多次的回车键的.这种情况下显然没有办法用ReadLn来处理. 我们可以用以下方法来接收数据: procedure

IDHTTP-HTTPS通讯方法(Indy10.2.3之前仅支持OpenSSL的0.9.8以前的版本)

加载https的站点页面内容的时候记得在窗体上加上“IdSSLIOHandlerSocketOpenSSL1” 以及idhttp里面IOHandler为“IdSSLIOHandlerSocketOpenSSL1” 不然老报“IOHandler value is not valid.”错误. dnspod API V2.0 就是用的https 用delphi开发客户 只需要用idhttp就可以post 在界面上放一个TIdHTTP控件,命名为IdHTTP1,再放一个TIdSSLIOHandlerS

indy10安装方法

首先要卸载Delphi7中的Indy9. 卸载方法如下:1.进入D7的目录,双击Borland Delphi7.msi.2.在弹出的对话框中选"Modify".3.然后点"Next",在接下来的对话框中,找到Indy,点"Do Not Install".之后一路"Next",最后完成,就卸载成功了. 安装:1.把下列路径加入Delphi的Library Pathindy10\Source\Coreindy10\Source\P

Indy10 控件的使用(2)TidTCpServer组件学习

Indy10 控件的使用(2)TidTCpServer组件学习 (2012-05-18 15:16:53) 转载▼ 标签: indy10 lazarus idtcpserver 分类: Indy10 以下来自英文原版帮助文件,文桓英语不好,翻译了老半天.有错误的地方见谅,别骂我. TIdTCPServer = class(TIdComponent) Description TIdTCPServer is a TIdComponent descendant that encapsulates a