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)那後果過是很嚴重的。
程序員

相關文章
相關標籤/搜索