Indy Changed from Indy10
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.
Indy Changed from Indy10的更多相关文章
- Indy10.2.5的危险做法
		
为了排查一个Bug今天无意看了看Indy源码,结果吓了一跳.TIdIOHandler.ReadLongWord函数用于读取通讯数据并转换成LongWord类型返回,它做用了一种危险的做法可能会导致数据 ...
 - Delphi组件indy 10中IdTCPServer修正及SSL使用心得
		
indy 10终于随着Delphi2005发布了,不过indy套件在我的印象中总是复杂并且BUG不断,说实话,不是看在他一整套组件的面子上,我还是喜欢VCL原生的Socket组件,简洁,清晰.Indy ...
 - Indy的TCPServer到底能支持多少个连接
		
最近一个项目,最开始使用IdTcpServer,在大压力测试的时候,只连接了800个多一点的客户端(每个客户端连接上之后每秒钟发送一个几十字节的报文,服务器应答).但是持续的时间不会超过10分钟,服务 ...
 - Delphi indy线程控件TIdThreadComponent的使用
		
当程序需要做耗时操作,例如访问数据库获取较多的数据.获取大文件MD5.网络访问数据量比较大.界面需要频繁刷新等等,都可以用线程来解决界面卡顿的问题,从而优化用户体验. 在知道TIdThreadComp ...
 - Indy 10.5.8 for Delphi and Lazarus 修改版(2011)
		
Indy 10.5.8 for Delphi and Lazarus 修改版(2011) Internet Direct(Indy)是一组开放源代码的Internet组件,涵盖了几乎所有流行的I ...
 - Delphi 7~XE系列升级安装Indy10.6
		
由于低版本Indy无法满足网络技术的日益更新,如SSL/TLS请求.RawHeaders与Cookie管理等问题处理. 我本身一直在用Delphi 2007,因为D2009开始底层的编码已不同,旧项目 ...
 - indy10的idhttpServer应答字符串
		
indy10的idhttpServer应答字符串 先看应答字符串的代码: procedure TIdIOHandler.Write(const AOut: string; AByteEncoding: ...
 - Delphi7卸载indy9,安装indy10步骤
		
1. 找到C:\Program Files\Borland\Delphi7\Borland Delphi7.msi——双击——点Next——选择Modify,点Next——找到Program File ...
 - Delphi中Indy 10的安装和老版本的卸载
		
http://www.cnblogs.com/railgunman/archive/2010/08/31/1814112.html Indy 10的安装和老版本的卸载 Indy 10下载地址: htt ...
 
随机推荐
- IOS 沙盒与清除缓存
			
SandBox,沙盒机制,是一种安全体系.我们所开发的每一个应用程序在设备上会有一个对应的沙盒文件夹,当前的程序只能在自己的沙盒文件夹中读取文件,不能访问其他应用程序的沙盒.在项目中添加的所有非代码的 ...
 - android 数据加密——加密的概述
			
数据加密又称密码学,它是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文.数据加密目前仍是计算机系统对信息进行保护的一种最可靠的办法.它利 ...
 - Java 读取 .properties 配置文件
			
java 开发中,经常要读取 properties 配置文件,下面介绍几种读取方式: 1.基于 InputStream 读取配置文件 该方式的优点在于可以读取任意路径下的配置文件 Properties ...
 - CentOS下ssh sftp配置及权限设置
			
运营有异地传输文件的需求,但如果通过QQ等即时通讯软件,不利于文件的集中管理,不方便.而我们办公室的内网机器无法提供外网访问方法,且传输的内容不合适放到公共的网盘或者是云存储上,所以只能用线上负载较低 ...
 - nginx不浏览直接下载文件
			
当我们使用Nginx时,如果要让一些附件比如txt,pdf,doc等不直接在浏览器打开,而弹出另存为的对话框(也就是下载),则可以在nginx里添加如下配置: location /{if ($requ ...
 - capwap学习笔记——初识capwap(三)
			
2.5.6 CAPWAP状态机详解 2.5.6.1 Start to Idle 这个状态变迁发生在设备初始化完成. ¢ WTP: 开启CAPWAP状态机. ¢ AC: 开启CAPWAP状 ...
 - 如何用Javascript检测到所有的IE版本
			
如何用Javascript检测到所有的IE版本 function GetIEVersion() { var sAgent = window.navigator.userAgent; var Idx = ...
 - 今天发现一个神奇的网站Greasy Fork
			
Greasy Fork这个网站的神奇之处在于,提供了各路大神编写的脚本,可以在浏览器中实现各种神奇的功能,比如这个: 我下载使用了,确实好用,什么腾讯视频vip,爱奇艺视频vip,统统可以观看~ 并且 ...
 - CSS外框高度自动适应
			
当有浮动float时,最外框会不跟随内容的高度而高: 解决办法一:清除浮动 clear:both <!DOCTYPE html> <html xmlns="http:// ...
 - 从n个数中随机选取m个
			
咋一看,这是个很简单的问题,但是如果n是个不确定的数呢?比如服务器每天会收到数以亿计的请求,但是目前服务器端不希望保存所有的请求,只想随机保存这些请求中的m个.试设计一种算法,能够使服务器实时保存m个 ...