一. 潜在的二进制Form文件的不兼容
过去,新版本Delphi创建的二进制Form文件(或称DFM文件)可以被老版本的Delphi读取。但是现在不行了。某些二进制Form文件可能不能被老版本正确的读取,其原因是Delphi 6内部的字符串的流化和原先不同。过去,流化操作假设一个本地特殊的字符集。而现在新的流化操作假设字符集为UTF-8。由此带来的问题就是,如果Delphi 6的二进制Form文件中包含有码值大于127的字符出现(比如版权符®),则该文件就不能被Delphi 的老版本正确读取。
如果你想在老版本的Delphi 中打开Delphi 6 的Form文件,那么请先将该Form文件存为文本格式而非二进制格式。
Potential binary form file incompatibilities
In the past, binary form files (or DFM files) created with newer versions of Delphi could be read by older versions. This is no longer true in Delphi 6; some binary form files may be read incorrectly because of the way that Delphi 6 performs internal string streaming. In the past, streaming was performed assuming a locale specific character set. Now streaming assumes that the character set is UTF-8. As a consequence, if there are characters with a code greater than 127 (such as the copyright symbol ? in a Delphi 6 binary form file, that file cannot be read by older versions of Delphi.
If you intend to use a Delphi 6 form file (including older form files imported into and modified with Delphi 6) in an older version of Delphi, the file should be saved in text format instead of binary format.
二. 有关可赋值的常量
编译宏$WRITEABLECONST现在的缺省值改为关,这是为了防止Delphi的工程中运用可赋值的常量。可赋值的常量,也就是定义一个常量,但是却允许在运行期间改变其值。例子如下:
const
foo: Integer = 12;
begin
foo := 14;
end.
在以往的Delphi版本中,有这么一个特性:常量不是真正的常量。使用编译宏$WRITEABLECONST OFF,则以上的代码中的Begin和End之间的Foo的赋值将引发一个编译错误。若要避免它,只需将Foo的声明改为 var。
你可能有将常量用作一个可以初始化的局部变量的代码,比如:
procedure MyProc;
const
somedata: Integer = 12;
begin
Inc(somedata, 3);
end;
你要做的是将局部常量移到过程的外部声明,使其成为一个全局的变量。然后代码变为:
var
somedata: Integer = 12;
procedure MyProc;
begin
Inc(somedata, 3);
end;
对于过度依赖于常量的代码(比如ActiveX 控件的包装器),可以通过在源文件中插入一个{$WRITEABLECONST ON}的编译命令来修正。这一特性,在RTL, VCL, CLX,和 DB 等核心的源代码中被禁止使用,但是在周边的单元比如ActiveX 控件的包装器中倒可以接受。
总而言之,你应该意识到“可赋值的常量”这个说法的自相矛盾。Delphi的以往版本中的这一特性,只是为了与老的16位的编译器的兼容而保留,但现在对于Delphi的开发者来说已经毫无意义了。要养成好的编程习惯,尽量避免使用可赋值的常量。
Change in writeable constants
The $WRITEABLECONST compiler switch ( aka $J ) now has a default state of OFF, which will prevent Delphi projects from having writeable constants. Writeable constants refers to the use of a typed constant as a variable modifiable at runtime. Here is an example:
const
foo: Integer = 12;
begin
foo := 14;
end.
In prior releases of Delphi, this was an acceptable construct; constants weren't really constant. With $WRITEABLECONST OFF, this code will now produce a compile error on the assignment to the foo variable in the begin..end block. To fix it, simply change the const declaration to a var declaration.
You may have code that uses a typed const as an initialized local variable with global lifetime, like this:
procedure MyProc;
const
somedata: Integer = 12;
begin
Inc(somedata, 3);
end;
You will need to move the local const out of the procedure and declare it for what it is: a global variable. After making this change, the code segment above becomes:
var
somedata: Integer = 12;
procedure MyProc;
begin
Inc(somedata, 3);
end;
Code that relies heavily on the typed const quirk (such as the ActiveX control wrapper generator) can insert a {$WRITEABLECONST ON} directive in the source file as a quick fix. This practice is forbidden in the RTL, VCL, CLX, and DB source code and discouraged in the IDE sources, but acceptable for fringe units such as ActiveX control wrappers.
In general, you should note that the phrase "writeable constant" is an oxymoron. Prior versions of Delphi allowed them by default to maintain compatibility with an older 16-bit compiler, which is no longer important for most Delphi developers. Use good programming practice; avoid writeable constants.
三. Cardinal类型的负数值
过去,Delphi处理Cardinal类型的负数值时使用32位的机制,这样使得结果为一些零头的值(Cardinal类型允许的最大的值与当前值的差加一)。以下为例子:
var
c: Cardinal;
i: Int64;
begin
c := 4294967294;
i := -c;
WriteLn(i);
end;
在以往版本的Delphi中,I的值应当是2。但是这种情况下这个值明显不对。Delphi 6中,Cardinal类型是先转化为64位的有符号类型,然后取其负数值,所以最终结果I的值为-4294967294。
可能有已经存在的代码依赖于原先错误的Cardinal负数值的实现方法。读者应当对Delphi 的这一新特性引起足够的重视。花足够多的时间来检验你的代码中是否使用了对Cardianl的值的取负数是很值得的,同时确信一点,Delphi的这个新的特性对你的程序的正确性不构成影响。
Unary negation of Cardinal type
In the past, Delphi handled unary negation of Cardinal type numbers using 32 bit operations, which could lead to some odd results. Here is an example of code which uses unary negation:
var
c: Cardinal;
i: Int64;
begin
c := 4294967294;
i := -c;
WriteLn(i);
end;
In previous versions of Delphi, the value of i displayed would be 2. This is obviously incorrect behavior for this case. In Delphi 6, the unary negation is handled after promoting the Cardinal type to a 64 bit signed type, so the final value of i displayed is -4294967294.
It is possible that existing code may rely on the incorrect behavior of unary negation. Delphi users should be aware of this new behavior. It may be worth your time to check your code for instances of unary negation of Cardinal variables, and make sure that your application responds to the new behavior appropriately.
四. 单元DsgnIntf改名及相关变化
工程中对于DsgnIntf的引用,需要更新到一个新的名字:DesignIntf。可能还得加上DesignEditors,VCLEditors 和RTLConsts 到你的引用列表中。并且你还得将designide加入到你的Package的Requires的列表中。对dsnide50的引用可能得改为DesignIde,如果Delphi没有自动更改的话。
任何引用了IDesigner的运行期Package,需要用IdesignerHook来防止运行期时需要designide。运动期代码中,IDesignerHook 足以应付。设计时间的代码也可以使用IDesigner,但是代码要象下例一样:
var
RealDesigner: IDesigner;
...
SomeDesignerHook.QueryInterface(IDesigner,RealDesigner);
...
从IDesignerHook 的一个实例上获得真正的IDesigner接口。IDesignerHook的使用只需要引用Classes和Forms两个单元。IDesigner还需要用DesignIntf,该单元被包含在许多其它Packatge中,而其中的一些可能导致不可再次分发。
Borland在此希望感谢Field的测试员Matt Palcic,感谢他让我们对此引起注意。
DsgnIntf renamed and related changes
References to DsgnIntf in your project should be changed to the new Delphi 6 name, DesignIntf. You may also need to add DesignEditors, VCLEditors and RTLConsts to your uses clause. You will also need to add designide to your package's requires list. References to dsnide50 should probably also be changed to designide if that isn't changed automatically by Delphi.
Any runtime packages that use IDesigner need to use IDesignerHook to avoid a requirement of designide at runtime. In runtime code, IDesignerHook should suffice. Design-time code can use IDesigner, but should use something like
var
RealDesigner: IDesigner;
...
SomeDesignerHook.QueryInterface(IDesigner,RealDesigner);
...
To get the real IDesigner interface from an instance of IDesignerHook. IDesignerHook only requires Classes and Forms to be available. IDesigner requires DesignIntf, which includes many other packages, some of which may not be redistributable.
Borland wishes to thank field tester Matt Palcic for bringing these changes to our attention.
五. 组件编辑器的变化
Delphi 6中,类TComponentEditor有了不同的祖先。在Delphi 5中,它从TInterfacedObject
继承而来;现在它从一个新的类,TbaseComponentEditor继承而来。同时,TComponentEditorClass也变为TbaseComponentEditor的类类型,而不是TComponentEditor的类类型。这些体系结构上的变化可能需要你修改你的老的Delphi的工程。
Component editor changes
The class TComponentEditor has a different ancestry in Delphi 6. In Delphi 5, it descended from TInterfacedObject; it now descends from a new class, TBaseComponentEditor. Also, the class TComponentEditorClass is now a class of TBaseComponentEditor instead of TComponentEditor. These changes in hierarchy may require you to modify your older Delphi projects.
Borland wishes to thank field tester Clive Walden for bringing these changes to our attention.