admin 管理员组

文章数量: 1086019


2023年12月17日发(作者:evoke)

Delphi7升级到Delphi 2010、Delphi XE、Delphi XE2总结 .

Delphi7升级到Delphi 2010、Delphi XE、Delphi XE2总结 .

Delphi7升级到Delphi 2010、Delphi XE、Delphi XE2总结

这两天把一个使用Delphi2007成功升级到了Delphi2010。升级途中很艰辛,总结了 以下经验与大家分享。另外,D7使用的第三方组件,由于官方没有发布For Delphi2010的更新,修改的第三 方组件列表见文章尾部。

1,PChar

因为Delphi不支持无类型指针的算术运算,很多程序员使用 PChar来代替Pointer,即使指针指向目标并不是PAnsiChar。

考虑如下代码:

var

P:PChar;

Buffer:Pointer;

begin

GetMem(Buffer,255);

P:=Buffer;

p^:=#1; Inc(P);

p^:=#2;

FreeMem(Buffer,255);

end;

在2010中PChar已经不再表示PAnsiChar而是表示PWideChar,如果依然这样写,运行时很可能会得到一个内存访问错误。因为每 次Inc(P),实际上指针向前移动了2字节,因为SizeOf(WideChar)=2,Inc(P)相当于

P:=P+SizeOf(WideChar)。

解决方法是把PChar替换成PAnsiChar2,Move FillChar

CopyMemory

这些函数依赖的是字节长度,往往我们直接使用Length(Str)来获取,这是行不通的。

考虑如下代码:

var

P1,P2:String;

begin

P1:='test';

SetLength(P2,Length(P1));

Move(P1[1],P2[1],Length(P1));end

在2010中String默认映射到UnicodeString,单个字符是2字节,所以上文中P1实际占用了8字节内存,而传给Move函数的长 度只有4字节,最终结果是P2="te"。

解决办法1:

修改String为AnsiString,该方案虽然可行,但你的程序就享受不到Unicode待遇了。

解决办法2:

SetLength 函数不要修改,因为他的长度参数是字符长度,而不是字节长度。

Move函数的最后一个参数 Length(P1) 修改成

Length(P1)*SizeOf(Char)。

注意:不要偷懒使用万一老师说的ByteLength函数,该函

数并没有For AnsiString的重载,编译器会 把参数隐式转化为UnicodeString然后,ByteLength函数计算UnicodeString的长度。例如:一旦你不小心传入了一个

AnsiString类型长度为4的字符串,函数会返回8,而不是你期望的长度4。3,Key in ['a'..'z','B','C']

这类代码最好替换成CharInSet(Key,['a'..'z','B','C']) 不然会当作AnsiChar处理。4,WideString

代码中的所有WideString都考虑替换成String,现在

WideString只是为了与COM兼容而存在,且没有引用计数,性能低下。5,Tnt控件

如果你的工程使用了Tnt控件或以前的WideTextPos

WideStringReplace之类的东西都替换成标准的吧,不用曲线救国了。

---------经过修改,可以在Delphi2010下运作的第三方组件--------------

1,PNGDelphi

2,EmbeddedWB

3,SynEdit的语法高亮组件 unihighlighter

4,JEDI Win32API Header这些组件现在可以在Delphi2010下运作了。

6,引用AnsiStrings单元

如果你有必要使用 AnsiUpperCase AnsiLowerCase

AnsiCompareStr之类的函数,一定要引用AnsiStrings单元。

如果你不引用该单元,即便编译不报错,你实际上是用的还是Unicode版本的函数,会有隐式的转化。不信你打开参数自动完成,看看IDE提示给你的类型是什么?天啊AnsiLowerCase参数竟然还是String,而不是AnsiString。看来Delphi2010太迫切的要抛弃Ansi字符串了,以至于你不引用AnsiStrings单元,所有Ansixxxx函数实际上还是Unicode版本。7,AnsiCopy AnsiPos AnsiDelete

不要用AnsiCopy AnsiPos AnsiDelete,因为Copy Pos

Delete三个函数已经有了For Ansi的重载。8,把Char转化为小写用什么?

答案:试试看Character单元的新函数 ToUpper ToLower。以前我都是用System里面的UpCase函数,现在依然可用

不过却找不到LowCase DownCase之类的函数,困扰我好久好久。索性全使用Character单元提供的新函数吧。9,编译期警告:[DCC Warning] (31): W1057 Implicit

string cast from 'AnsiString' to 'string'

如果你的代码中包含了两种字符串(Unicode、Ansi)之间进行隐式转化的时候就会出现该提示。

如下代码就会触发该警告:var Unicode:String;

Ansi:AnsiString; begin Ansi:='test..'; Unicode:=Ansi;

把旧版本的Delphi项目升级到2010,我通常都是借助编译警告来快速寻找需要改动的部分。通常你可以把赋值双方都声明为String(默认影射到UnicodeString),就可以避免该警告。但如果你确定必须在此处保留Ansi并进行转化的时候,建议你显式的转化他们(例如:Unicode:=String(Ansi);),这样可以避免该警告,方便你在升级过程中继续寻找其他需要修改的地方。10,Readln

Writeln 写入文件时候要注意

如果你传给Writeln一个AnsiString,那么它也会在文件中写入AnsiString,那么你读取得时候就必须传给Readln一个AnsiString的类型,否则就是乱码。例如旧工程的配置文

件是Ansi的,而你已经把相关读取配置的代码升级为支持Unicode,那么运行工程前你首先要用记事本之类的工具把配置文件另存为成Unicode编码。当然你还要注意跳过Unicode文件头的两个字节FE

FF。11,别再用String来操作二进制数据了

一定要记住String只是字符串,不要把它当作缓冲区、内存流使用。我的项目中,有很多地方是使用字符串来处理二进制数据,导致在本次升级中颇为费脑。如果当时用TBytes或TStream就好了。

反面教材:

var Int1,Int2,Int3,Int4:Integer; Buf:String; begin

SetLength(Buf,12); Move(Int1,Buf[1],SizeOf(Integer));

Move(Int1,Buf[5],SizeOf(Integer));

Move(Int1,Buf[9],SizeOf(Integer)); Buf:=Buf+'前面有3个Integer。';

12,还是PChar

注意在2010中是这样的:

PChar= Pointer to a WideChar array;

PAnsiChar = Pointer to a AnsiChar array;

如果你还像是在Delphi 7中那样:PChar(AnsiString)那后果过是很严重的。一段转换例子

D7

unit ReCode;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms,

Dialogs;

Function JiaMi(Src:String; Key:String):String;

Function JieMi(Src:String; Key:String):String;

implementation

Function JiaMi(Src:String; Key:String):String;

var

KeyLen :Integer;

KeyPos :Integer;

offset :Integer;

dest :String;

SrcPos :Integer;

SrcAsc :Integer;

Range :Integer;

begin

KeyLen:=Length(Key);

KeyPos:=0;

Range:=1;

Randomize;

offset:=Random(Range);

dest:=format('%1.2x',[offset]);

for SrcPos := 1 to Length(Src) do

begin

SrcAsc:=(Ord(Src[SrcPos]) + offset) MOD 255;

if KeyPos < KeyLen then KeyPos:= KeyPos + 1 else

KeyPos:=1;

SrcAsc:= SrcAsc xor Ord(Key[KeyPos]);

dest:=dest + format('%1.2x',[SrcAsc]);

offset:=SrcAsc;

end;

Result:=Dest;

end;

//解密函数

Function JieMi (Src:String; Key:String):String;

var

KeyLen :Integer;

KeyPos :Integer;

offset :Integer;

dest :String;

SrcPos :Integer;

SrcAsc :Integer;

TmpSrcAsc :Integer;

Range :Integer;

begin

KeyLen:=Length(Key);

if KeyLen = 0 then key:='starlin';

KeyPos:=0;

SrcPos:=0;

SrcAsc:=0;

Range:=1;

offset:=StrToInt('$'+ copy(src,1,2));

SrcPos:=3;

repeat

try

SrcAsc:=StrToInt('$'+ copy(src,SrcPos,2));

except

SrcAsc:=StrToInt('$00');

end;

if KeyPos < KeyLen Then KeyPos := KeyPos + 1 else

KeyPos := 1;

TmpSrcAsc := SrcAsc xor Ord(Key[KeyPos]);

if TmpSrcAsc <= offset then

TmpSrcAsc := 255 + TmpSrcAsc - offset

else

TmpSrcAsc := TmpSrcAsc - offset;

dest := dest + chr(TmpSrcAsc);

offset:=srcAsc;

SrcPos:=SrcPos + 2;

until SrcPos >= Length(Src);

Result:=Dest;

Result:=Copy(Result,1,Length(Result)-1);

end;

5unit ReCode;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms,

Dialogs,AnsiStrings;

Function JiaMi(Src:String; Key:String):String;

Function JieMi(Src:String; Key:String):String;

implementation

Function JiaMi(Src:String; Key:String):String;

var

KeyLen :Integer;

KeyPos :Integer;

offset :Integer;

dest :String;

SrcPos :Integer;

SrcAsc :Integer;

Range :Integer;

IntTemp:integer;

SrcAnsi:PAnsiChar;

begin

KeyLen:=Length(Key);

KeyPos:=0;

Range:=1;

Randomize;

offset:=Random(Range);

dest:=format('%1.2x',[offset]);

SrcAnsi:=PAnsiChar(AnsiString(Src));

IntTemp:= Length(SrcAnsi);

for SrcPos := 1 to IntTemp do

begin

SrcAsc:=(Ord(SrcAnsi[SrcPos-1]) + offset) MOD 255;

if KeyPos < KeyLen then KeyPos:= KeyPos + 1 else

KeyPos:=1;

SrcAsc:= SrcAsc xor Ord(Key[KeyPos]);

dest:=dest + format('%1.2x',[SrcAsc]);

offset:=SrcAsc;

end;

Result:=Dest;

end;

//解密函数

Function JieMi (Src:String; Key:String):String;

var

KeyLen :Integer;

KeyPos :Integer;

offset :Integer;

dest :String;

SrcPos :Integer;

SrcAsc :Integer;

TmpSrcAsc :Integer;

Range :Integer;

SrcAnsi:PAnsiChar;

IntTemp,i:Integer;

ByteArray: array of Byte;

begin

KeyLen:=Length(Key);

if KeyLen = 0 then key:='starlin';

KeyPos:=0;

SrcPos:=0;

SrcAsc:=0;

Range:=1;

offset:=StrToInt('$'+ copy(src,1,2));

SrcPos:=3;

IntTemp:=Length(Src) div 2;

setlength(ByteArray,IntTemp);

i:=0;

repeat

try

SrcAsc:=StrToInt('$'+ copy(src,SrcPos,2));

except

SrcAsc:=StrToInt('$00');

end;

if KeyPos < KeyLen Then KeyPos := KeyPos + 1 else

KeyPos := 1;

TmpSrcAsc := SrcAsc xor Ord(Key[KeyPos]);

if TmpSrcAsc <= offset then

TmpSrcAsc := 255 + TmpSrcAsc - offset

else

TmpSrcAsc := TmpSrcAsc - offset;

ByteArray[i]:=TmpSrcAsc;

i:=i+1;

offset:=srcAsc;

SrcPos:=SrcPos + 2;

until SrcPos >= Length(Src);

CopyMemory(@SrcAnsi[0],@ByteArray[0],IntTemp);

dest:=string((SrcAnsi));

Result:=Dest;

end;


本文标签: 函数 使用 长度 升级 字节