Delphi2007升级到Delphi 2010总结

这两天把一个使用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替换成PAnsiChar 



2,Move FillChar CopyMemory
这些函数依赖的是字节长度,每每咱们直接使用Length(Str)来获取,这是行不通的。

考虑以下代码:

var
   P1,P2:String;
begin
   P1:='test';
   SetLength(P2,Length(P1));
   Move(P1[1],P2[1],Length(P1));
在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单元
若是你有必要使用 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] Unit1.pas(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)那后果过是很严重的。
程序员

相关文章
相关标签/搜索